{"file_path":"contracts-0.8/governance/Validators.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.7 <0.8.20;\n\nimport \"@openzeppelin/contracts8/access/Ownable.sol\";\nimport \"@openzeppelin/contracts8/utils/math/Math.sol\";\nimport \"@openzeppelin/contracts8/utils/math/SafeMath.sol\";\nimport \"solidity-bytes-utils-8/contracts/BytesLib.sol\";\n\nimport \"../../contracts/governance/interfaces/IValidators.sol\";\n\nimport \"../../contracts/common/Initializable.sol\";\nimport \"../../contracts/common/FixidityLib.sol\";\nimport \"../common/linkedlists/AddressLinkedList.sol\";\nimport \"../common/UsingRegistry.sol\";\nimport \"../common/PrecompilesOverride.sol\";\nimport \"../../contracts/common/interfaces/ICeloVersionedContract.sol\";\nimport \"../../contracts/common/libraries/ReentrancyGuard.sol\";\nimport \"../common/interfaces/IStableToken.sol\";\n\nimport \"../../contracts/common/interfaces/IAccounts.sol\";\n\n/**\n * @title A contract for registering and electing Validator Groups and Validators.\n */\ncontract Validators is\n  IValidators,\n  ICeloVersionedContract,\n  Ownable,\n  ReentrancyGuard,\n  Initializable,\n  UsingRegistry,\n  PrecompilesOverride\n{\n  using FixidityLib for FixidityLib.Fraction;\n  using AddressLinkedList for LinkedList.List;\n  using SafeMath for uint256;\n  using BytesLib for bytes;\n\n  // For Validators, these requirements must be met in order to:\n  //   1. Register a validator\n  //   2. Affiliate with and be added to a group\n  //   3. Receive epoch payments (note that the group must meet the group requirements as well)\n  // Accounts may de-register their Validator `duration` seconds after they were last a member of a\n  // group, after which no restrictions on Locked Gold will apply to the account.\n  //\n  // For Validator Groups, these requirements must be met in order to:\n  //   1. Register a group\n  //   2. Add a member to a group\n  //   3. Receive epoch payments\n  // Note that for groups, the requirement value is multiplied by the number of members, and is\n  // enforced for `duration` seconds after the group last had that number of members.\n  // Accounts may de-register their Group `duration` seconds after they were last non-empty, after\n  // which no restrictions on Locked Gold will apply to the account.\n  struct LockedGoldRequirements {\n    uint256 value;\n    // In seconds.\n    uint256 duration;\n  }\n\n  struct ValidatorGroup {\n    bool exists;\n    LinkedList.List members;\n    FixidityLib.Fraction commission;\n    FixidityLib.Fraction nextCommission;\n    uint256 nextCommissionBlock;\n    // sizeHistory[i] contains the last time the group contained i members.\n    uint256[] sizeHistory;\n    SlashingInfo slashInfo;\n    // Commission on voter CELO rewards (independent from validator payment commission above).\n    // Groups set this to take a percentage of epoch rewards that would otherwise go to voters.\n    // Currently active commission rate, applied at distribution time in EpochManager.\n    FixidityLib.Fraction voterRewardCommission;\n    // Pending commission rate queued via setNextVoterRewardCommissionUpdate, not yet active.\n    FixidityLib.Fraction nextVoterRewardCommission;\n    // Block at which the queued nextVoterRewardCommission becomes activatable via\n    // updateVoterRewardCommission. Set to block.number + commissionUpdateDelay at queue time.\n    uint256 nextVoterRewardCommissionBlock;\n  }\n\n  // Stores the epoch number at which a validator joined a particular group.\n  struct MembershipHistoryEntry {\n    uint256 epochNumber;\n    address group;\n  }\n\n  // Stores the per-epoch membership history of a validator, used to determine which group\n  // commission should be paid to at the end of an epoch.\n  // Stores a timestamp of the last time the validator was removed from a group, used to determine\n  // whether or not a group can de-register.\n  struct MembershipHistory {\n    // The key to the most recent entry in the entries mapping.\n    uint256 tail;\n    // The number of entries in this validators membership history.\n    uint256 numEntries;\n    mapping(uint256 => MembershipHistoryEntry) entries;\n    uint256 lastRemovedFromGroupTimestamp;\n  }\n\n  struct SlashingInfo {\n    FixidityLib.Fraction multiplier;\n    uint256 lastSlashed;\n  }\n\n  struct PublicKeys {\n    bytes ecdsa;\n    bytes bls;\n  }\n\n  struct Validator {\n    PublicKeys publicKeys;\n    address affiliation;\n    FixidityLib.Fraction score;\n    MembershipHistory membershipHistory;\n  }\n\n  // Parameters that govern the calculation of validator's score.\n  struct ValidatorScoreParameters {\n    uint256 exponent;\n    FixidityLib.Fraction adjustmentSpeed;\n  }\n\n  struct InitParams {\n    // The number of blocks to delay a ValidatorGroup's commission\n    uint256 commissionUpdateDelay;\n  }\n\n  mapping(address => ValidatorGroup) private groups;\n  mapping(address => Validator) private validators;\n  address[] private registeredGroups;\n  address[] private registeredValidators;\n  LockedGoldRequirements public validatorLockedGoldRequirements;\n  LockedGoldRequirements public groupLockedGoldRequirements;\n  ValidatorScoreParameters private deprecated_validatorScoreParameters;\n  uint256 public membershipHistoryLength;\n  uint256 public maxGroupSize;\n  // The number of blocks to delay a ValidatorGroup's commission update\n  uint256 public commissionUpdateDelay;\n  uint256 public slashingMultiplierResetPeriod;\n  uint256 public deprecated_downtimeGracePeriod;\n\n  // Cap on voter reward commission to protect voters from excessive commission rates.\n  // Set via governance. Defaults to 0 (commissions disabled until governance sets a value).\n  // Set to FixidityLib.fixed1() for unlimited.\n  FixidityLib.Fraction public maxVoterRewardCommission;\n\n  // Block number of the most recent reduction of maxVoterRewardCommission. Queued voter\n  // reward commission updates whose activation block is at or before this block are\n  // invalidated and must be re-queued. This prevents a matured-but-unactivated queued\n  // update from reviving after governance lowers (e.g. to 0) and later restores the cap.\n  uint256 public maxVoterRewardCommissionLastReducedBlock;\n\n  event MaxGroupSizeSet(uint256 size);\n  event CommissionUpdateDelaySet(uint256 delay);\n  event GroupLockedGoldRequirementsSet(uint256 value, uint256 duration);\n  event ValidatorLockedGoldRequirementsSet(uint256 value, uint256 duration);\n  event MembershipHistoryLengthSet(uint256 length);\n  event ValidatorRegistered(address indexed validator);\n  event ValidatorDeregistered(address indexed validator);\n  event ValidatorAffiliated(address indexed validator, address indexed group);\n  event ValidatorDeaffiliated(address indexed validator, address indexed group);\n  event ValidatorEcdsaPublicKeyUpdated(address indexed validator, bytes ecdsaPublicKey);\n  event ValidatorGroupRegistered(address indexed group, uint256 commission);\n  event ValidatorGroupDeregistered(address indexed group);\n  event ValidatorGroupMemberAdded(address indexed group, address indexed validator);\n  event ValidatorGroupMemberRemoved(address indexed group, address indexed validator);\n  event ValidatorGroupMemberReordered(address indexed group, address indexed validator);\n  event ValidatorGroupCommissionUpdateQueued(\n    address indexed group,\n    uint256 commission,\n    uint256 activationBlock\n  );\n  event ValidatorGroupCommissionUpdated(address indexed group, uint256 commission);\n  event ValidatorGroupVoterRewardCommissionUpdateQueued(\n    address indexed group,\n    uint256 commission,\n    uint256 activationBlock\n  );\n  event ValidatorGroupVoterRewardCommissionUpdated(address indexed group, uint256 commission);\n  event MaxVoterRewardCommissionSet(uint256 maxCommission);\n\n  modifier onlySlasher() {\n    require(getLockedGold().isSlasher(msg.sender), \"Only registered slasher can call\");\n    _;\n  }\n\n  /**\n   * @notice Sets initialized == true on implementation contracts\n   * @param test Set to true to skip implementation initialization\n   */\n  constructor(bool test) Initializable(test) {}\n\n  /**\n   * @notice Used in place of the constructor to allow the contract to be upgradable via proxy.\n   * @param registryAddress The address of the registry core smart contract.\n   * @param groupRequirementValue The Locked Gold requirement amount for groups.\n   * @param groupRequirementDuration The Locked Gold requirement duration for groups.\n   * @param validatorRequirementValue The Locked Gold requirement amount for validators.\n   * @param validatorRequirementDuration The Locked Gold requirement duration for validators.\n   * @param _membershipHistoryLength The max number of entries for validator membership history.\n   * @param _maxGroupSize The maximum group size.\n   * update.\n   * @dev Should be called only once.\n   */\n  function initialize(\n    address registryAddress,\n    uint256 groupRequirementValue,\n    uint256 groupRequirementDuration,\n    uint256 validatorRequirementValue,\n    uint256 validatorRequirementDuration,\n    uint256 _membershipHistoryLength,\n    uint256 _slashingMultiplierResetPeriod,\n    uint256 _maxGroupSize,\n    InitParams calldata initParams\n  ) external initializer {\n    _transferOwnership(msg.sender);\n    setRegistry(registryAddress);\n    setGroupLockedGoldRequirements(groupRequirementValue, groupRequirementDuration);\n    setValidatorLockedGoldRequirements(validatorRequirementValue, validatorRequirementDuration);\n    setMaxGroupSize(_maxGroupSize);\n    setCommissionUpdateDelay(initParams.commissionUpdateDelay);\n    setMembershipHistoryLength(_membershipHistoryLength);\n    setSlashingMultiplierResetPeriod(_slashingMultiplierResetPeriod);\n  }\n\n  /**\n   * @notice Registers a validator unaffiliated with any validator group.\n   * @param ecdsaPublicKey The ECDSA public key that the validator is using for consensus, should\n   *   match the validator signer. 64 bytes.\n   * @return True upon success.\n   * @dev Fails if the account is already a validator or validator group.\n   * @dev Fails if the account does not have sufficient Locked Gold.\n   */\n  function registerValidator(bytes calldata ecdsaPublicKey) external nonReentrant returns (bool) {\n    return registerValidatorNoBls(ecdsaPublicKey);\n  }\n\n  /**\n   * @notice De-registers a validator.\n   * @param index The index of this validator in the list of all registered validators.\n   * @return True upon success.\n   * @dev Fails if the account is not a validator.\n   * @dev Fails if the validator has been a member of a group too recently.\n   */\n  function deregisterValidator(uint256 index) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidator(account), \"Not a validator\");\n\n    // Require that the validator has not been a member of a validator group for\n    // `validatorLockedGoldRequirements.duration` seconds.\n    Validator storage validator = validators[account];\n    if (validator.affiliation != address(0)) {\n      require(\n        !groups[validator.affiliation].members.contains(account),\n        \"Has been group member recently\"\n      );\n    }\n    uint256 requirementEndTime = validator.membershipHistory.lastRemovedFromGroupTimestamp.add(\n      validatorLockedGoldRequirements.duration\n    );\n    require(requirementEndTime < block.timestamp, \"Not yet requirement end time\");\n\n    // Remove the validator.\n    deleteElement(registeredValidators, account, index);\n    delete validators[account];\n    emit ValidatorDeregistered(account);\n    return true;\n  }\n\n  /**\n   * @notice Affiliates a validator with a group, allowing it to be added as a member.\n   * @param group The validator group with which to affiliate.\n   * @return True upon success.\n   * @dev De-affiliates with the previously affiliated group if present.\n   */\n  function affiliate(address group) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidator(account), \"Not a validator\");\n    require(isValidatorGroup(group), \"Not a validator group\");\n    require(meetsAccountLockedGoldRequirements(account), \"Validator doesn't meet requirements\");\n    require(meetsAccountLockedGoldRequirements(group), \"Group doesn't meet requirements\");\n    Validator storage validator = validators[account];\n    if (validator.affiliation != address(0)) {\n      _deaffiliate(validator, account);\n    }\n    validator.affiliation = group;\n    emit ValidatorAffiliated(account, group);\n    return true;\n  }\n\n  /**\n   * @notice De-affiliates a validator, removing it from the group for which it is a member.\n   * @return True upon success.\n   * @dev Fails if the account is not a validator with non-zero affiliation.\n   */\n  function deaffiliate() external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidator(account), \"Not a validator\");\n    Validator storage validator = validators[account];\n    require(validator.affiliation != address(0), \"deaffiliate: not affiliated\");\n    _deaffiliate(validator, account);\n    return true;\n  }\n\n  /**\n   * @notice Updates a validator's ECDSA key.\n   * @param account The address under which the validator is registered.\n   * @param signer The address which the validator is using to sign consensus messages.\n   * @param ecdsaPublicKey The ECDSA public key corresponding to `signer`.\n   * @return True upon success.\n   */\n  function updateEcdsaPublicKey(\n    address account,\n    address signer,\n    bytes calldata ecdsaPublicKey\n  ) external onlyRegisteredContract(ACCOUNTS_REGISTRY_ID) returns (bool) {\n    require(isValidator(account), \"Not a validator\");\n    Validator storage validator = validators[account];\n    require(\n      _updateEcdsaPublicKey(validator, account, signer, ecdsaPublicKey),\n      \"Error updating ECDSA public key\"\n    );\n    return true;\n  }\n\n  /**\n   * @notice De-registers a validator group.\n   * @param index The index of this validator group in the list of all validator groups.\n   * @return True upon success.\n   * @dev Fails if the account is not a validator group with no members.\n   * @dev Fails if the group has had members too recently.\n   */\n  function deregisterValidatorGroup(uint256 index) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    // Only Validator Groups that have never had members or have been empty for at least\n    // `groupLockedGoldRequirements.duration` seconds can be deregistered.\n    require(isValidatorGroup(account), \"Not a validator group\");\n    require(groups[account].members.numElements == 0, \"Validator group not empty\");\n    uint256[] storage sizeHistory = groups[account].sizeHistory;\n    if (sizeHistory.length > 1) {\n      require(\n        sizeHistory[1].add(groupLockedGoldRequirements.duration) < block.timestamp,\n        \"Hasn't been empty for long enough\"\n      );\n    }\n    delete groups[account];\n    deleteElement(registeredGroups, account, index);\n    emit ValidatorGroupDeregistered(account);\n    return true;\n  }\n\n  /**\n   * @notice Registers a validator group with no member validators.\n   * @param commission Fixidity representation of the commission this group receives on epoch\n   *   payments made to its members.\n   * @return True upon success.\n   * @dev Fails if the account is already a validator or validator group.\n   * @dev Fails if the account does not have sufficient weight.\n   */\n  function registerValidatorGroup(uint256 commission) external nonReentrant returns (bool) {\n    require(commission <= FixidityLib.fixed1().unwrap(), \"Commission can't be greater than 100%\");\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    _isRegistrationAllowed(account);\n    require(!isValidator(account), \"Already registered as validator\");\n    require(!isValidatorGroup(account), \"Already registered as group\");\n    uint256 lockedGoldBalance = getLockedGold().getAccountTotalLockedGold(account);\n    require(lockedGoldBalance >= groupLockedGoldRequirements.value, \"Not enough locked gold\");\n    ValidatorGroup storage group = groups[account];\n    group.exists = true;\n    group.commission = FixidityLib.wrap(commission);\n    group.slashInfo = SlashingInfo(FixidityLib.fixed1(), 0);\n    registeredGroups.push(account);\n    emit ValidatorGroupRegistered(account, commission);\n    return true;\n  }\n\n  /**\n   * @notice Adds a member to the end of a validator group's list of members.\n   * @param validator The validator to add to the group\n   * @return True upon success.\n   * @dev Fails if `validator` has not set their affiliation to this account.\n   * @dev Fails if the group has zero members.\n   */\n  function addMember(address validator) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(groups[account].members.numElements > 0, \"Validator group empty\");\n    return _addMember(account, validator, address(0), address(0));\n  }\n\n  /**\n   * @notice Adds the first member to a group's list of members and marks the group eligible for election.\n   * @param validator The validator to add to the group\n   * @param lesser The address of the group that has received fewer votes than this group.\n   * @param greater The address of the group that has received more votes than this group.\n   * @return True upon success.\n   * @dev Fails if `validator` has not set their affiliation to this account.\n   * @dev Fails if the group has > 0 members.\n   */\n  function addFirstMember(\n    address validator,\n    address lesser,\n    address greater\n  ) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(groups[account].members.numElements == 0, \"Validator group not empty\");\n    return _addMember(account, validator, lesser, greater);\n  }\n\n  /**\n   * @notice Removes a member from a validator group.\n   * @param validator The validator to remove from the group\n   * @return True upon success.\n   * @dev Fails if `validator` is not a member of the account's group.\n   */\n  function removeMember(address validator) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account) && isValidator(validator), \"is not group and validator\");\n    return _removeMember(account, validator);\n  }\n\n  /**\n   * @notice Reorders a member within a validator group.\n   * @param validator The validator to reorder.\n   * @param lesserMember The member who will be behind `validator`, or 0 if `validator` will be the\n   *   last member.\n   * @param greaterMember The member who will be ahead of `validator`, or 0 if `validator` will be\n   *   the first member.\n   * @return True upon success.\n   * @dev Fails if `validator` is not a member of the account's validator group.\n   */\n  function reorderMember(\n    address validator,\n    address lesserMember,\n    address greaterMember\n  ) external nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account), \"Not a group\");\n    require(isValidator(validator), \"Not a validator\");\n    ValidatorGroup storage group = groups[account];\n    require(group.members.contains(validator), \"Not a member of the group\");\n    group.members.update(validator, lesserMember, greaterMember);\n    emit ValidatorGroupMemberReordered(account, validator);\n    return true;\n  }\n\n  /**\n   * @notice Queues an update to a validator group's commission.\n   * If there was a previously scheduled update, that is overwritten.\n   * @param commission Fixidity representation of the commission this group receives on epoch\n   *   payments made to its members. Must be in the range [0, 1.0].\n   */\n  function setNextCommissionUpdate(uint256 commission) external {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    require(commission <= FixidityLib.fixed1().unwrap(), \"Commission can't be greater than 100%\");\n    require(commission != group.commission.unwrap(), \"Commission must be different\");\n\n    group.nextCommission = FixidityLib.wrap(commission);\n    group.nextCommissionBlock = block.number.add(commissionUpdateDelay);\n    emit ValidatorGroupCommissionUpdateQueued(account, commission, group.nextCommissionBlock);\n  }\n\n  /**\n   * @notice Updates a validator group's commission based on the previously queued update\n   */\n  function updateCommission() external {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n\n    _sendValidatorGroupPaymentsIfNecessary(group);\n\n    require(group.nextCommissionBlock != 0, \"No commission update queued\");\n    require(group.nextCommissionBlock <= block.number, \"Can't apply commission update yet\");\n\n    group.commission = group.nextCommission;\n    delete group.nextCommission;\n    delete group.nextCommissionBlock;\n    emit ValidatorGroupCommissionUpdated(account, group.commission.unwrap());\n  }\n\n  /**\n   * @notice Queues an update to a validator group's voter reward commission.\n   * If there was a previously scheduled update, that is overwritten.\n   * @param commission Fixidity representation of the commission this group receives on epoch\n   *   voter rewards. Must be in the range [0, 1.0] and below maxVoterRewardCommission if set.\n   */\n  function setNextVoterRewardCommissionUpdate(uint256 commission) external {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    FixidityLib.Fraction memory commissionFraction = FixidityLib.wrap(commission);\n    require(\n      commissionFraction.lte(FixidityLib.fixed1()),\n      \"Voter reward commission can't be greater than 100%\"\n    );\n    require(\n      commissionFraction.lte(maxVoterRewardCommission),\n      \"Voter reward commission exceeds max allowed\"\n    );\n    // Reject no-op queues. The value that would otherwise take effect is the pending\n    // queued value when an update is already queued, or the active commission otherwise.\n    // Comparing against the active value alone would make it impossible to overwrite a\n    // stale non-zero queued value with 0 once the active commission was already 0\n    // (e.g. after governance lowered the cap to 0).\n    FixidityLib.Fraction memory currentTarget = group.nextVoterRewardCommissionBlock != 0\n      ? group.nextVoterRewardCommission\n      : group.voterRewardCommission;\n    require(!commissionFraction.equals(currentTarget), \"Voter reward commission must be different\");\n\n    group.nextVoterRewardCommission = commissionFraction;\n    uint256 activationBlock = block.number + commissionUpdateDelay;\n    group.nextVoterRewardCommissionBlock = activationBlock;\n    emit ValidatorGroupVoterRewardCommissionUpdateQueued(account, commission, activationBlock);\n  }\n\n  /**\n   * @notice Updates a validator group's voter reward commission based on the previously queued\n   * update.\n   */\n  function updateVoterRewardCommission() external {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n\n    // Prevent activating a new commission while an epoch is being processed. Otherwise a group\n    // could change its rate between setToProcessGroups and individual processGroup calls,\n    // applying the new rate to already-earned voter rewards for the closed epoch.\n    require(\n      !getEpochManager().isEpochProcessingStarted(),\n      \"Cannot update voter reward commission during epoch processing\"\n    );\n\n    require(group.nextVoterRewardCommissionBlock != 0, \"No voter reward commission update queued\");\n    require(\n      group.nextVoterRewardCommissionBlock <= block.number,\n      \"Can't apply voter reward commission update yet\"\n    );\n\n    // Invalidate updates that matured before governance reduced the cap. Without this,\n    // a queued update blocked by a cap reduction (e.g. to 0) would silently revive and\n    // activate without a fresh delay once the cap was restored.\n    require(\n      group.nextVoterRewardCommissionBlock > maxVoterRewardCommissionLastReducedBlock,\n      \"Voter reward commission cap reduced since queued; re-queue required\"\n    );\n\n    // Re-check max cap at activation time. Governance may have lowered the cap since the\n    // update was queued.\n    require(\n      group.nextVoterRewardCommission.lte(maxVoterRewardCommission),\n      \"Voter reward commission exceeds max allowed\"\n    );\n\n    group.voterRewardCommission = group.nextVoterRewardCommission;\n    group.nextVoterRewardCommission = FixidityLib.wrap(0);\n    group.nextVoterRewardCommissionBlock = 0;\n    emit ValidatorGroupVoterRewardCommissionUpdated(account, group.voterRewardCommission.unwrap());\n  }\n\n  /**\n   * @notice Removes a validator from the group for which it is a member.\n   * @param validatorAccount The validator to deaffiliate from their affiliated validator group.\n   */\n  function forceDeaffiliateIfValidator(address validatorAccount) external nonReentrant onlySlasher {\n    if (isValidator(validatorAccount)) {\n      Validator storage validator = validators[validatorAccount];\n      if (validator.affiliation != address(0)) {\n        _deaffiliate(validator, validatorAccount);\n      }\n    }\n  }\n\n  /**\n   * @notice Resets a group's slashing multiplier if it has been >= the reset period since\n   *         the last time the group was slashed.\n   */\n  function resetSlashingMultiplier() external nonReentrant {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    require(\n      block.timestamp >= group.slashInfo.lastSlashed.add(slashingMultiplierResetPeriod),\n      \"`resetSlashingMultiplier` called before resetPeriod expired\"\n    );\n    group.slashInfo.multiplier = FixidityLib.fixed1();\n  }\n\n  /**\n   * @notice Halves the group's slashing multiplier.\n   * @param account The group being slashed.\n   */\n  function halveSlashingMultiplier(address account) external nonReentrant onlySlasher {\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    group.slashInfo.multiplier = FixidityLib.wrap(group.slashInfo.multiplier.unwrap().div(2));\n    group.slashInfo.lastSlashed = block.timestamp;\n  }\n\n  // TODO: Move this function's logic to `EpochManager` once Mento updates stable token\n  // to allow `EpochManager` to mint.\n  /**\n   * @notice Allows the EpochManager contract to mint stable token for itself.\n   * @param amount The amount of stableToken to be minted.\n   */\n  function mintStableToEpochManager(\n    uint256 amount\n  ) external nonReentrant onlyRegisteredContract(EPOCH_MANAGER_REGISTRY_ID) {\n    require(\n      IStableToken(getStableToken()).mint(msg.sender, amount),\n      \"mint failed to epoch manager\"\n    );\n  }\n\n  function getMembershipHistoryLength() external view returns (uint256) {\n    return membershipHistoryLength;\n  }\n\n  /**\n   * @notice Returns validator group information.\n   * @param account The account that registered the validator group.\n   * @return keys The Keys.\n   * @return commision The commision.\n   * @return nextCommision The next commision.\n   * @return nextCommisionBlock The next commision block.\n   * @return size The Size history.\n   * @return multiplier The multiplier.\n   * @return lastSlashed The last slashed.\n   */\n  function getValidatorGroup(\n    address account\n  )\n    external\n    view\n    returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256)\n  {\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    return (\n      group.members.getKeys(),\n      group.commission.unwrap(),\n      group.nextCommission.unwrap(),\n      group.nextCommissionBlock,\n      group.sizeHistory,\n      group.slashInfo.multiplier.unwrap(),\n      group.slashInfo.lastSlashed\n    );\n  }\n\n  /**\n   * @notice Returns the voter reward commission for a validator group.\n   * @param account The address of the validator group.\n   * @return The current voter reward commission (Fixidity).\n   * @return The queued voter reward commission (Fixidity).\n   * @return The block at which the queued commission activates.\n   */\n  function getVoterRewardCommission(\n    address account\n  ) external view returns (uint256, uint256, uint256) {\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    return (\n      group.voterRewardCommission.unwrap(),\n      group.nextVoterRewardCommission.unwrap(),\n      group.nextVoterRewardCommissionBlock\n    );\n  }\n\n  /**\n   * @notice Returns the top n group members for a particular group.\n   * @param account The address of the validator group.\n   * @param n The number of members to return.\n   * @return The signers of the top n group members for a particular group.\n   */\n  function getTopGroupValidators(\n    address account,\n    uint256 n\n  ) external view returns (address[] memory) {\n    address[] memory topAccounts = groups[account].members.headN(n);\n    address[] memory topValidators = new address[](n);\n\n    IAccounts accounts = getAccounts();\n\n    for (uint256 i = 0; i < n; i = i.add(1)) {\n      topValidators[i] = accounts.getValidatorSigner(topAccounts[i]);\n    }\n    return topValidators;\n  }\n\n  /**\n   * @notice Retreives the top validator accounts of the specified group.\n   * @param account The address of the validator group.\n   * @param n The number of members to return.\n   * @return The accounts of the top n group members for a particular group.\n   */\n  function getTopGroupValidatorsAccounts(\n    address account,\n    uint256 n\n  ) external view returns (address[] memory) {\n    address[] memory topAccounts = groups[account].members.headN(n);\n    return topAccounts;\n  }\n\n  /**\n   * @notice Returns the number of members in the provided validator groups.\n   * @param accounts The addresses of the validator groups.\n   * @return The number of members in the provided validator groups.\n   */\n  function getGroupsNumMembers(\n    address[] calldata accounts\n  ) external view returns (uint256[] memory) {\n    uint256[] memory numMembers = new uint256[](accounts.length);\n    for (uint256 i = 0; i < accounts.length; i = i.add(1)) {\n      numMembers[i] = getGroupNumMembers(accounts[i]);\n    }\n    return numMembers;\n  }\n\n  /**\n   * @notice Returns the number of registered validators.\n   * @return The number of registered validators.\n   */\n  function getNumRegisteredValidators() external view returns (uint256) {\n    return registeredValidators.length;\n  }\n\n  /**\n   * @notice Returns the Locked Gold requirements for validators.\n   * @return The Locked Gold value.\n   * @return The Locked Gold duration.\n   */\n  function getValidatorLockedGoldRequirements() external view returns (uint256, uint256) {\n    return (validatorLockedGoldRequirements.value, validatorLockedGoldRequirements.duration);\n  }\n\n  /**\n   * @notice Returns the Locked Gold requirements for validator groups.\n   * @return The Locked Gold value.\n   * @return The Locked Gold duration.\n   */\n  function getGroupLockedGoldRequirements() external view returns (uint256, uint256) {\n    return (groupLockedGoldRequirements.value, groupLockedGoldRequirements.duration);\n  }\n\n  /**\n   * @notice Returns the list of signers for the registered validator accounts.\n   * @return The list of signers for registered validator accounts.\n   */\n  function getRegisteredValidatorSigners() external view returns (address[] memory) {\n    IAccounts accounts = getAccounts();\n    address[] memory signers = new address[](registeredValidators.length);\n    for (uint256 i = 0; i < signers.length; i = i.add(1)) {\n      signers[i] = accounts.getValidatorSigner(registeredValidators[i]);\n    }\n    return signers;\n  }\n\n  /**\n   * @notice Returns the list of registered validator accounts.\n   * @return The list of registered validator accounts.\n   */\n  function getRegisteredValidators() external view returns (address[] memory) {\n    return registeredValidators;\n  }\n\n  /**\n   * @notice Returns the list of registered validator group accounts.\n   * @return The list of registered validator group addresses.\n   */\n  function getRegisteredValidatorGroups() external view returns (address[] memory) {\n    return registeredGroups;\n  }\n\n  /**\n   * @notice Returns the group that `account` was a member of at the end of the last epoch.\n   * @param signer The signer of the account whose group membership should be returned.\n   * @return The group that `account` was a member of at the end of the last epoch.\n   */\n  function getMembershipInLastEpochFromSigner(address signer) external view returns (address) {\n    address account = getAccounts().signerToAccount(signer);\n    require(isValidator(account), \"Not a validator\");\n    return getMembershipInLastEpoch(account);\n  }\n\n  /**\n   * @notice Getter for a group's slashing multiplier.\n   * @param account The group to fetch slashing multiplier for.\n   */\n  function getValidatorGroupSlashingMultiplier(address account) external view returns (uint256) {\n    require(isValidatorGroup(account), \"Not a validator group\");\n    ValidatorGroup storage group = groups[account];\n    return group.slashInfo.multiplier.unwrap();\n  }\n\n  /**\n   * @notice Returns the group that `account` was a member of during `epochNumber`.\n   * @param account The account whose group membership should be returned.\n   * @param epochNumber The epoch number we are querying this account's membership at.\n   * @param index The index into the validator's history struct for their history at `epochNumber`.\n   * @return The group that `account` was a member of during `epochNumber`.\n   */\n  function groupMembershipInEpoch(\n    address account,\n    uint256 epochNumber,\n    uint256 index\n  ) external view returns (address) {\n    require(isValidator(account), \"Not a validator\");\n    require(epochNumber <= getEpochNumber(), \"Epoch cannot be larger than current\");\n    MembershipHistory storage history = validators[account].membershipHistory;\n    require(index < history.tail.add(history.numEntries), \"index out of bounds\");\n    require(index >= history.tail && history.numEntries > 0, \"index out of bounds\");\n    bool isExactMatch = history.entries[index].epochNumber == epochNumber;\n    bool isLastEntry = index.sub(history.tail) == history.numEntries.sub(1);\n    bool isWithinRange = history.entries[index].epochNumber < epochNumber &&\n      (history.entries[index.add(1)].epochNumber > epochNumber || isLastEntry);\n    require(\n      isExactMatch || isWithinRange,\n      \"provided index does not match provided epochNumber at index in history.\"\n    );\n    return history.entries[index].group;\n  }\n\n  /**\n   * @notice Returns the group membership history of a validator.\n   * @param account The validator whose membership history to return.\n   * @return epochs The epochs of a validator.\n   * @return The membership groups of a validator.\n   * @return The last removed from group timestamp of a validator.\n   * @return The tail of a validator.\n   */\n  function getMembershipHistory(\n    address account\n  ) external view returns (uint256[] memory, address[] memory, uint256, uint256) {\n    MembershipHistory storage history = validators[account].membershipHistory;\n    uint256[] memory epochs = new uint256[](history.numEntries);\n    address[] memory membershipGroups = new address[](history.numEntries);\n    for (uint256 i = 0; i < history.numEntries; i = i.add(1)) {\n      uint256 index = history.tail.add(i);\n      epochs[i] = history.entries[index].epochNumber;\n      membershipGroups[i] = history.entries[index].group;\n    }\n    return (epochs, membershipGroups, history.lastRemovedFromGroupTimestamp, history.tail);\n  }\n\n  /**\n   * @notice Returns the maximum number of members a group can add.\n   * @return The maximum number of members a group can add.\n   */\n  function getMaxGroupSize() external view returns (uint256) {\n    return maxGroupSize;\n  }\n\n  /**\n   * @notice Returns the block delay for a ValidatorGroup's commission udpdate.\n   * @return The block delay for a ValidatorGroup's commission udpdate.\n   */\n  function getCommissionUpdateDelay() external view returns (uint256) {\n    return commissionUpdateDelay;\n  }\n\n  /**\n   * @notice Computes epoch payments to the account\n   * @param account The validator account of the validator to distribute the epoch payment to.\n   * @param maxPayment The maximum payment to the validator. Actual payment is based on score and\n   *   group commission.\n   * @return The total payment paid to the validator and their group.\n   */\n  function computeEpochReward(\n    address account,\n    uint256 score,\n    uint256 maxPayment\n  ) external view virtual returns (uint256) {\n    if (!isValidator(account)) {\n      // In the unlikely scenario that the validator is still in the set after it has deaffiliated\n      // skip the payment. This is only possible if the epochs have not been processed for more than the time\n      // defined in validatorLockedGoldRequirements.duration. (currently 60 days)\n      return 0;\n    }\n    FixidityLib.Fraction memory scoreFraction = FixidityLib.wrap(score);\n    require(scoreFraction.lte(FixidityLib.fixed1()), \"Score must be <= 1\");\n\n    // The group that should be paid is the group that the validator was a member of at the\n    // time it was elected.\n    address group = getMembershipInLastEpoch(account);\n    require(group != address(0), \"Validator not registered with a group\");\n    // Both the validator and the group must maintain the minimum locked gold balance in order to\n    // receive epoch payments.\n    if (meetsAccountLockedGoldRequirements(account) && meetsAccountLockedGoldRequirements(group)) {\n      FixidityLib.Fraction memory totalPayment = FixidityLib\n        .newFixed(maxPayment)\n        .multiply(scoreFraction)\n        .multiply(groups[group].slashInfo.multiplier);\n      return totalPayment.fromFixed();\n    } else {\n      return 0;\n    }\n  }\n\n  /**\n   * @notice Returns the storage, major, minor, and patch version of the contract.\n   * @return Storage version of the contract.\n   * @return Major version of the contract.\n   * @return Minor version of the contract.\n   * @return Patch version of the contract.\n   */\n  function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {\n    return (1, 4, 1, 0);\n  }\n\n  /**\n   * @notice Registers a validator unaffiliated with any validator group.\n   * @param ecdsaPublicKey The ECDSA public key that the validator is using for consensus, should\n   *   match the validator signer. 64 bytes.\n   * @return True upon success.\n   * @dev Fails if the account is already a validator or validator group.\n   * @dev Fails if the account does not have sufficient Locked Gold.\n   * @dev Will be deprecated in favor of `registerValidator(bytes calldata ecdsaPublicKey)`.\n   */\n  function registerValidatorNoBls(\n    bytes calldata ecdsaPublicKey\n  ) public nonReentrant returns (bool) {\n    address account = getAccounts().validatorSignerToAccount(msg.sender);\n    _isRegistrationAllowed(account);\n    require(!isValidator(account) && !isValidatorGroup(account), \"Already registered\");\n    uint256 lockedGoldBalance = getLockedGold().getAccountTotalLockedGold(account);\n    require(lockedGoldBalance >= validatorLockedGoldRequirements.value, \"Deposit too small\");\n    Validator storage validator = validators[account];\n    address signer = getAccounts().getValidatorSigner(account);\n    require(\n      _updateEcdsaPublicKey(validator, account, signer, ecdsaPublicKey),\n      \"Error updating ECDSA public key\"\n    );\n    registeredValidators.push(account);\n    updateMembershipHistory(account, address(0));\n    emit ValidatorRegistered(account);\n    return true;\n  }\n\n  /**\n   * @notice Updates the block delay for a ValidatorGroup's commission update\n   * @param delay Number of blocks to delay the update\n   */\n  function setCommissionUpdateDelay(uint256 delay) public onlyOwner {\n    require(delay != commissionUpdateDelay, \"commission update delay not changed\");\n    commissionUpdateDelay = delay;\n    emit CommissionUpdateDelaySet(delay);\n  }\n\n  /**\n   * @notice Sets the maximum voter reward commission that groups can set.\n   * @param maxCommission Fixidity representation of the max commission.\n   *   Defaults to 0 (commissions disabled). Set to FixidityLib.fixed1() for unlimited.\n   */\n  function setMaxVoterRewardCommission(uint256 maxCommission) external onlyOwner {\n    // Block during epoch processing so all groups in the same epoch see the same effective cap\n    // when EpochManager._deductVoterRewardCommission clamps voter commissions at distribution time.\n    require(\n      !getEpochManager().isEpochProcessingStarted(),\n      \"Cannot update max voter reward commission during epoch processing\"\n    );\n\n    FixidityLib.Fraction memory maxCommissionFraction = FixidityLib.wrap(maxCommission);\n    require(\n      maxCommissionFraction.lte(FixidityLib.fixed1()),\n      \"Max voter reward commission can't be greater than 100%\"\n    );\n    require(\n      !maxCommissionFraction.equals(maxVoterRewardCommission),\n      \"Max voter reward commission not changed\"\n    );\n    // Record reductions so that previously queued updates cannot silently revive once the\n    // cap is later restored; they must be re-queued instead.\n    if (maxCommissionFraction.lt(maxVoterRewardCommission)) {\n      maxVoterRewardCommissionLastReducedBlock = block.number;\n    }\n    maxVoterRewardCommission = maxCommissionFraction;\n    emit MaxVoterRewardCommissionSet(maxCommission);\n  }\n\n  /**\n   * @notice Updates the maximum number of members a group can have.\n   * @param size The maximum group size.\n   * @return True upon success.\n   */\n  function setMaxGroupSize(uint256 size) public onlyOwner returns (bool) {\n    require(0 < size, \"Max group size cannot be zero\");\n    require(size != maxGroupSize, \"Max group size not changed\");\n    maxGroupSize = size;\n    emit MaxGroupSizeSet(size);\n    return true;\n  }\n\n  /**\n   * @notice Updates the number of validator group membership entries to store.\n   * @param length The number of validator group membership entries to store.\n   * @return True upon success.\n   */\n  function setMembershipHistoryLength(uint256 length) public onlyOwner returns (bool) {\n    require(0 < length, \"Membership history length cannot be zero\");\n    require(length != membershipHistoryLength, \"Membership history length not changed\");\n    membershipHistoryLength = length;\n    emit MembershipHistoryLengthSet(length);\n    return true;\n  }\n\n  /**\n   * @notice Updates the Locked Gold requirements for Validator Groups.\n   * @param value The per-member amount of Locked Gold required.\n   * @param duration The time (in seconds) that these requirements persist for.\n   * @return True upon success.\n   */\n  function setGroupLockedGoldRequirements(\n    uint256 value,\n    uint256 duration\n  ) public onlyOwner returns (bool) {\n    LockedGoldRequirements storage requirements = groupLockedGoldRequirements;\n    require(\n      value != requirements.value || duration != requirements.duration,\n      \"Group requirements not changed\"\n    );\n    groupLockedGoldRequirements = LockedGoldRequirements(value, duration);\n    emit GroupLockedGoldRequirementsSet(value, duration);\n    return true;\n  }\n\n  /**\n   * @notice Updates the Locked Gold requirements for Validators.\n   * @param value The amount of Locked Gold required.\n   * @param duration The time (in seconds) that these requirements persist for.\n   * @return True upon success.\n   */\n  function setValidatorLockedGoldRequirements(\n    uint256 value,\n    uint256 duration\n  ) public onlyOwner returns (bool) {\n    LockedGoldRequirements storage requirements = validatorLockedGoldRequirements;\n    require(\n      value != requirements.value || duration != requirements.duration,\n      \"Validator requirements not changed\"\n    );\n    validatorLockedGoldRequirements = LockedGoldRequirements(value, duration);\n    emit ValidatorLockedGoldRequirementsSet(value, duration);\n    return true;\n  }\n\n  /**\n   * @notice Sets the slashingMultiplierRestPeriod property if called by owner.\n   * @param value New reset period for slashing multiplier.\n   */\n  function setSlashingMultiplierResetPeriod(uint256 value) public nonReentrant onlyOwner {\n    slashingMultiplierResetPeriod = value;\n  }\n\n  /**\n   * @notice Returns the current locked gold balance requirement for the supplied account.\n   * @param account The account that may have to meet locked gold balance requirements.\n   * @return The current locked gold balance requirement for the supplied account.\n   */\n  function getAccountLockedGoldRequirement(address account) public view returns (uint256) {\n    if (isValidator(account)) {\n      return validatorLockedGoldRequirements.value;\n    } else if (isValidatorGroup(account)) {\n      uint256 multiplier = Math.max(1, groups[account].members.numElements);\n      uint256[] storage sizeHistory = groups[account].sizeHistory;\n      if (sizeHistory.length > 0) {\n        for (uint256 i = sizeHistory.length.sub(1); i > 0; i = i.sub(1)) {\n          if (sizeHistory[i].add(groupLockedGoldRequirements.duration) >= block.timestamp) {\n            multiplier = Math.max(i, multiplier);\n            break;\n          }\n        }\n      }\n      return groupLockedGoldRequirements.value.mul(multiplier);\n    }\n    return 0;\n  }\n\n  /**\n   * @notice Returns the group that `account` was a member of at the end of the last epoch.\n   * @param account The account whose group membership should be returned.\n   * @return The group that `account` was a member of at the end of the last epoch.\n   */\n  function getMembershipInLastEpoch(address account) public view returns (address) {\n    uint256 epochNumber = getEpochNumber();\n\n    MembershipHistory storage history = validators[account].membershipHistory;\n    uint256 head = history.numEntries == 0 ? 0 : history.tail.add(history.numEntries.sub(1));\n    // If the most recent entry in the membership history is for the current epoch number, we need\n    // to look at the previous entry.\n    if (history.entries[head].epochNumber == epochNumber) {\n      if (head > history.tail) {\n        head = head.sub(1);\n      }\n    }\n    return history.entries[head].group;\n  }\n\n  /**\n   * @notice Returns whether or not an account meets its Locked Gold requirements.\n   * @param account The address of the account.\n   * @return Whether or not an account meets its Locked Gold requirements.\n   */\n  function meetsAccountLockedGoldRequirements(address account) public view returns (bool) {\n    uint256 balance = getLockedGold().getAccountTotalLockedGold(account);\n    // Add a bit of \"wiggle room\" to accommodate the fact that vote activation can result in ~1\n    // wei rounding errors. Using 10 as an additional margin of safety.\n    return balance.add(10) >= getAccountLockedGoldRequirement(account);\n  }\n\n  /**\n   * @notice Returns validator information.\n   * @param account The account that registered the validator.\n   * @return ecdsaPublicKey The ECDSA public key.\n   * @return blsPublicKey The BLS public key.\n   * @return affiliation The address of the validator group the validator is a member of.\n   * @return score The validator's score.\n   * @return signer The address of the validator's signer.\n   */\n  function getValidator(\n    address account\n  )\n    public\n    view\n    returns (\n      bytes memory ecdsaPublicKey,\n      bytes memory blsPublicKey,\n      address affiliation,\n      uint256 score,\n      address signer\n    )\n  {\n    require(isValidator(account), \"Not a validator\");\n    Validator storage validator = validators[account];\n    return (\n      validator.publicKeys.ecdsa,\n      validator.publicKeys.bls,\n      validator.affiliation,\n      validator.score.unwrap(),\n      getAccounts().getValidatorSigner(account)\n    );\n  }\n\n  /**\n   * @notice Returns affiliated group to validator.\n   * @param account The account that registered the validator.\n   * @return group The validator group.\n   */\n  function getValidatorsGroup(address account) public view returns (address group) {\n    require(isValidator(account), \"Not a validator\");\n    Validator storage validator = validators[account];\n    return validator.affiliation;\n  }\n\n  /**\n   * @notice Returns the number of members in a validator group.\n   * @param account The address of the validator group.\n   * @return The number of members in a validator group.\n   */\n  function getGroupNumMembers(address account) public view returns (uint256) {\n    require(isValidatorGroup(account), \"Not validator group\");\n    return groups[account].members.numElements;\n  }\n\n  /**\n   * @notice Returns whether a particular account has a registered validator group.\n   * @param account The account.\n   * @return Whether a particular address is a registered validator group.\n   */\n  function isValidatorGroup(address account) public view returns (bool) {\n    return groups[account].exists;\n  }\n\n  /**\n   * @notice Returns whether a particular account has a registered validator.\n   * @param account The account.\n   * @return Whether a particular address is a registered validator.\n   */\n  function isValidator(address account) public view returns (bool) {\n    return validators[account].publicKeys.ecdsa.length > 0;\n  }\n\n  function _isRegistrationAllowed(address account) private {\n    require(\n      !getElection().allowedToVoteOverMaxNumberOfGroups(account),\n      \"Cannot vote for more than max number of groups\"\n    );\n    require(\n      // Validator could avoid getting slashed by delegating Celo to delegatees that would be voting\n      // for lots of proposals. Such transaction could run out of gas.\n      getLockedGold().getAccountTotalDelegatedFraction(account) == 0,\n      \"Cannot delegate governance power\"\n    );\n  }\n\n  /**\n   * @notice Adds a member to the end of a validator group's list of members.\n   * @param group The address of the validator group.\n   * @param validator The validator to add to the group.\n   * @param lesser The address of the group that has received fewer votes than this group.\n   * @param greater The address of the group that has received more votes than this group.\n   * @return True upon success.\n   * @dev Fails if `validator` has not set their affiliation to this account.\n   * @dev Fails if the group has > 0 members.\n   */\n  function _addMember(\n    address group,\n    address validator,\n    address lesser,\n    address greater\n  ) private returns (bool) {\n    require(isValidatorGroup(group) && isValidator(validator), \"Not validator and group\");\n    ValidatorGroup storage _group = groups[group];\n    require(_group.members.numElements < maxGroupSize, \"group would exceed maximum size\");\n    require(validators[validator].affiliation == group, \"Not affiliated to group\");\n    require(!_group.members.contains(validator), \"Already in group\");\n    uint256 numMembers = _group.members.numElements.add(1);\n    _group.members.push(validator);\n    require(meetsAccountLockedGoldRequirements(group), \"Group requirements not met\");\n    require(meetsAccountLockedGoldRequirements(validator), \"Validator requirements not met\");\n    if (numMembers == 1) {\n      getElection().markGroupEligible(group, lesser, greater);\n    }\n    updateMembershipHistory(validator, group);\n    updateSizeHistory(group, numMembers.sub(1));\n    emit ValidatorGroupMemberAdded(group, validator);\n    return true;\n  }\n\n  /**\n   * @notice Updates a validator's ECDSA key.\n   * @param validator The validator whose ECDSA public key should be updated.\n   * @param signer The address with which the validator is signing consensus messages.\n   * @param ecdsaPublicKey The ECDSA public key that the validator is using for consensus. Should\n   *   match `signer`. 64 bytes.\n   * @return True upon success.\n   */\n  function _updateEcdsaPublicKey(\n    Validator storage validator,\n    address account,\n    address signer,\n    bytes memory ecdsaPublicKey\n  ) private returns (bool) {\n    require(ecdsaPublicKey.length == 64, \"Wrong ECDSA public key length\");\n    require(\n      address(uint160(uint256(keccak256(ecdsaPublicKey)))) == signer,\n      \"ECDSA key does not match signer\"\n    );\n    validator.publicKeys.ecdsa = ecdsaPublicKey;\n    emit ValidatorEcdsaPublicKeyUpdated(account, ecdsaPublicKey);\n    return true;\n  }\n\n  /**\n   * @notice Deletes an element from a list of addresses.\n   * @param list The list of addresses.\n   * @param element The address to delete.\n   * @param index The index of `element` in the list.\n   */\n  function deleteElement(address[] storage list, address element, uint256 index) private {\n    require(index < list.length && list[index] == element, \"deleteElement: index out of range\");\n    uint256 lastIndex = list.length.sub(1);\n    list[index] = list[lastIndex];\n    delete list[lastIndex];\n    list.pop();\n  }\n\n  /**\n   * @notice Removes a member from a validator group.\n   * @param group The group from which the member should be removed.\n   * @param validator The validator to remove from the group.\n   * @return True upon success.\n   * @dev If `validator` was the only member of `group`, `group` becomes unelectable.\n   * @dev Fails if `validator` is not a member of `group`.\n   */\n  function _removeMember(address group, address validator) private returns (bool) {\n    ValidatorGroup storage _group = groups[group];\n    require(validators[validator].affiliation == group, \"Not affiliated to group\");\n    require(_group.members.contains(validator), \"Not a member of the group\");\n    _group.members.remove(validator);\n    uint256 numMembers = _group.members.numElements;\n    // Empty validator groups are not electable.\n    if (numMembers == 0) {\n      getElection().markGroupIneligible(group);\n    }\n    updateMembershipHistory(validator, address(0));\n    updateSizeHistory(group, numMembers.add(1));\n    emit ValidatorGroupMemberRemoved(group, validator);\n    return true;\n  }\n\n  /**\n   * @notice Updates the group membership history of a particular account.\n   * @param account The account whose group membership has changed.\n   * @param group The group that the account is now a member of.\n   * @return True upon success.\n   * @dev Note that this is used to determine a validator's membership at the time of an election,\n   *   and so group changes within an epoch will overwrite eachother.\n   */\n  function updateMembershipHistory(address account, address group) private returns (bool) {\n    MembershipHistory storage history = validators[account].membershipHistory;\n    uint256 epochNumber = getEpochNumber();\n\n    uint256 head = history.numEntries == 0 ? 0 : history.tail.add(history.numEntries.sub(1));\n\n    if (history.numEntries > 0 && group == address(0)) {\n      history.lastRemovedFromGroupTimestamp = block.timestamp;\n    }\n\n    if (history.numEntries > 0 && history.entries[head].epochNumber == epochNumber) {\n      // There have been no elections since the validator last changed membership, overwrite the\n      // previous entry.\n      history.entries[head] = MembershipHistoryEntry(epochNumber, group);\n      return true;\n    }\n\n    // There have been elections since the validator last changed membership, create a new entry.\n    uint256 index = history.numEntries == 0 ? 0 : head.add(1);\n    history.entries[index] = MembershipHistoryEntry(epochNumber, group);\n    if (history.numEntries < membershipHistoryLength) {\n      // Not enough entries, don't remove any.\n      history.numEntries = history.numEntries.add(1);\n    } else if (history.numEntries == membershipHistoryLength) {\n      // Exactly enough entries, delete the oldest one to account for the one we added.\n      delete history.entries[history.tail];\n      history.tail = history.tail.add(1);\n    } else {\n      // Too many entries, delete the oldest two to account for the one we added.\n      delete history.entries[history.tail];\n      delete history.entries[history.tail.add(1)];\n      history.numEntries = history.numEntries.sub(1);\n      history.tail = history.tail.add(2);\n    }\n    return true;\n  }\n\n  /**\n   * @notice Updates the size history of a validator group.\n   * @param group The account whose group size has changed.\n   * @param size The new size of the group.\n   * @dev Used to determine how much gold an account needs to keep locked.\n   */\n  function updateSizeHistory(address group, uint256 size) private {\n    uint256[] storage sizeHistory = groups[group].sizeHistory;\n    if (size == sizeHistory.length) {\n      sizeHistory.push(block.timestamp);\n    } else if (size < sizeHistory.length) {\n      sizeHistory[size] = block.timestamp;\n    } else {\n      require(false, \"Unable to update size history\");\n    }\n  }\n\n  /**\n   * @notice De-affiliates a validator, removing it from the group for which it is a member.\n   * @param validator The validator to deaffiliate from their affiliated validator group.\n   * @param validatorAccount The LockedGold account of the validator.\n   * @return True upon success.\n   */\n  function _deaffiliate(\n    Validator storage validator,\n    address validatorAccount\n  ) private returns (bool) {\n    _sendValidatorPaymentIfNecessary(validatorAccount);\n    address affiliation = validator.affiliation;\n    ValidatorGroup storage group = groups[affiliation];\n    if (group.members.contains(validatorAccount)) {\n      _removeMember(affiliation, validatorAccount);\n    }\n    validator.affiliation = address(0);\n    emit ValidatorDeaffiliated(validatorAccount, affiliation);\n    return true;\n  }\n\n  function _sendValidatorPaymentIfNecessary(address validator) private {\n    getEpochManager().sendValidatorPayment(validator);\n  }\n\n  function _sendValidatorGroupPaymentsIfNecessary(ValidatorGroup storage group) private {\n    address[] memory members = group.members.getKeys();\n    for (uint256 i = 0; i < members.length; i++) {\n      _sendValidatorPaymentIfNecessary(members[i]);\n    }\n  }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106104cc5760003560e01c80638b16b1c611610283578063caf3c4261161015c578063e7f03766116100ce578063ee09831011610092578063ee09831014610a97578063eff2ea3f14610aaa578063f2fde38b14610abd578063facd743b14610ad0578063fae8db0a14610ae3578063fffdfccb14610af657600080fd5b8063e7f0376614610a4d578063ea4208ac14610a55578063eb17c1fe14610a68578063eb1d0b4214610a71578063ec68307214610a8457600080fd5b8063df4da46111610120578063df4da461146109f0578063e0e3ffe6146109f8578063e1497ff714610a01578063e33301aa14610a14578063e50e652d14610a27578063e5880d9a14610a3a57600080fd5b8063caf3c426146109a7578063d55dcbcf146109ba578063d93ab5ad146109c2578063dba94fcd146109ca578063dcff4cf6146109dd57600080fd5b8063b591d3a5116101f5578063bd9e9d94116101b9578063bd9e9d9414610947578063c10c96ef14610955578063c22d3bba14610960578063c54c1cd414610973578063c580514014610986578063ca6d56dc1461099457600080fd5b8063b591d3a514610909578063b6885a181461091c578063b8f9394314610924578063b915f5301461092c578063bb0f1fa51461093457600080fd5b80639a7b3be7116102475780639a7b3be71461089a5780639b2b592f146108a25780639b9d5161146108b5578063a09f7f55146108db578063a91ee0dc146108ee578063b16f3f7b1461090157600080fd5b80638b16b1c61461083d5780638da5cb5b146108505780638dd31e391461086157806397f742bf14610874578063988dcd1f1461088757600080fd5b806351b52225116103b55780636fa4764711610327578063789c9f3d116102eb578063789c9f3d146107db5780637b103999146107e4578063849a5205146107fc57806386d81a5a1461080f57806387ee8a0f146108225780638a8836261461082a57600080fd5b80636fa476471461077c5780637044775414610798578063715018a6146107b85780637385e5da146107c057806376c0a9ed146107c857600080fd5b80635d180adb116103795780635d180adb14610708578063602a9eee1461071b57806360fb822c1461072e57806367960e91146107415780636ab951a0146107545780636c620d901461076957600080fd5b806351b52225146106a057806352f13a4e146106b357806354255be0146106c65780635779e93d146106ec5780635a61d15b146106f557600080fd5b80633173b8db1161044e5780633f270898116104125780633f2708981461064c57806343d96699146106615780634b2c2f44146106695780634cd76db41461067c5780634e06fd8a14610685578063517f6d331461069857600080fd5b80633173b8db146105e757806335244f51146105fa57806336407b701461061d57806339e618e8146106265780633b1eb4bf1461063957600080fd5b8063123633ea11610495578063123633ea14610562578063158ef93e146105755780631858dd2f146105825780631904bb2e146105b057806323f0ab65146105d457600080fd5b8062253a70146104d1578063087c344e146104ee5780630b1ca49a146105015780630d1312b81461052457806311fb9e841461054f575b600080fd5b6012546104db9081565b6040519081526020015b60405180910390f35b6104db6104fc3660046175df565b610afe565b61051461050f366004617614565b610c79565b60405190151581526020016104e5565b610537610532366004617614565b610da4565b6040516001600160a01b0390911681526020016104e5565b61053761055d366004617631565b610e5a565b610537610570366004617631565b610f3f565b6002546105149060ff1681565b610595610590366004617614565b610f93565b604080519384526020840192909252908201526060016104e5565b6105c36105be366004617614565b611007565b6040516104e595949392919061769a565b6105146105e236600461779f565b611212565b6105146105f5366004617814565b6112a4565b61060d610608366004617614565b6113d5565b6040516104e594939291906178d3565b6104db60105481565b6104db610634366004617614565b611567565b6104db610647366004617631565b6115d4565b610654611671565b6040516104e5919061790c565b600e546104db565b6104db61067736600461791f565b6116d3565b6104db600d5481565b61051461069336600461799b565b6117e2565b6006546104db565b6105376106ae366004617614565b6119c0565b6105146106c1366004617614565b611a67565b6040805160018082526004602083015291810191909152600060608201526080016104e5565b6104db600e5481565b6105146107033660046179ff565b611a85565b6105376107163660046179ff565b611b50565b610514610729366004617a21565b611c55565b61051461073c366004617631565b611ca5565b6104db61074f36600461791f565b611f59565b610767610762366004617631565b61203b565b005b610767610777366004617631565b612087565b600954600a545b604080519283526020830191909152016104e5565b6107ab6107a6366004617a62565b612127565b6040516104e59190617ad6565b6107676121d3565b6104db6121e7565b6105146107d63660046179ff565b6121ff565b6104db60135481565b6002546105379061010090046001600160a01b031681565b61076761080a366004617631565b6122c7565b61076761081d366004617631565b612533565b6104db6126fb565b6104db61083836600461791f565b612782565b61051461084b366004617631565b61287d565b6000546001600160a01b0316610537565b61065461086f366004617ae9565b612b77565b610767610882366004617631565b612d50565b610514610895366004617814565b612f9b565b6104db613259565b6104db6108b0366004617631565b613264565b6108c86108c3366004617614565b613353565b6040516104e59796959493929190617b15565b6107676108e9366004617b63565b6134ca565b6107676108fc366004617614565b613584565b610767613634565b610514610917366004617614565b6139d9565b600d546104db565b610767613c13565b600f546104db565b610537610942366004617614565b613d9a565b600754600854610783919082565b600754600854610783565b61076761096e366004617614565b613de3565b610514610981366004617614565b613f6b565b600954600a54610783919082565b6105146109a2366004617614565b614001565b6105146109b5366004617a21565b614102565b610654614489565b6106546145bf565b6104db6109d8366004617614565b61461f565b6104db6109eb366004617614565b614678565b6104db614760565b6104db600f5481565b610514610a0f366004617631565b61484f565b610767610a22366004617614565b61493b565b6104db610a35366004617631565b614a76565b610654610a48366004617ae9565b614aa4565b610767614b42565b610767610a63366004617631565b614d0b565b6104db60115481565b610537610a7f3660046175df565b614ee2565b610783610a92366004617be7565b615169565b610514610aa5366004617631565b6152e9565b610514610ab8366004617631565b615645565b610767610acb366004617614565b615744565b610514610ade366004617614565b6157ba565b6104db610af1366004617631565b6157ea565b6105146158d7565b6000610b09846157ba565b610b1557506000610c72565b604080516020808201835260009091528151908101909152838152610b43610b3b615a31565b518251111590565b610b895760405162461bcd60e51b815260206004820152601260248201527153636f7265206d757374206265203c3d203160701b60448201526064015b60405180910390fd5b6000610b9486610da4565b90506001600160a01b038116610bfa5760405162461bcd60e51b815260206004820152602560248201527f56616c696461746f72206e6f7420726567697374657265642077697468206120604482015264067726f75760dc1b6064820152608401610b80565b610c0386613f6b565b8015610c135750610c1381613f6b565b15610c6b576001600160a01b03811660009081526003602090815260408083208151928301909152600901548152610c5690610c50858189615a59565b90615b17565b9050610c6181615e86565b9350505050610c72565b6000925050505b9392505050565b60006001806000828254610c8d9190617c40565b90915550506001546000610c9f615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015610ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d099190617c53565b9050610d1481611a67565b8015610d245750610d24846157ba565b610d705760405162461bcd60e51b815260206004820152601a60248201527f6973206e6f742067726f757020616e642076616c696461746f720000000000006044820152606401610b80565b610d7a8185615f48565b9250506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b50919050565b600080610daf613259565b6001600160a01b038416600090815260046020819052604082206005810154939450019115610e0057610dfb610df3600184600101546161e190919063ffffffff16565b8354906161ed565b610e03565b60005b6000818152600284016020526040902054909150839003610e35578154811115610e3557610e328160016161e1565b90505b6000908152600290910160205260409020600101546001600160a01b03169392505050565b60006018602160991b013b63ffffffff16610ec35760405162461bcd60e51b815260206004820152602360248201527f54686973206d6574686f64206973206e6f7420737570706f7274656420696e2060448201526226189760e91b6064820152608401610b80565b610ecb6161f9565b6001600160a01b0316638657f615836040518263ffffffff1660e01b8152600401610ef891815260200190565b602060405180830381865afa158015610f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f399190617c53565b92915050565b60006018602160991b013b63ffffffff1615610f8a57610f5d6161f9565b6001600160a01b0316632ba47274836040518263ffffffff1660e01b8152600401610ef891815260200190565b610f3982616234565b6000806000610fa184611a67565b610fbd5760405162461bcd60e51b8152600401610b8090617c98565b5050506001600160a01b031660009081526003602090815260409182902082518083018452600b820154908190528351928301909352600c81015491829052600d01549192909190565b6060806000806000611018866157ba565b6110345760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b0386811660009081526004602090815260409182902060028101548351928301909352600381015491829052928392600184019291169061107a615ea0565b604051634ce38b5f60e01b81526001600160a01b038d811660048301529190911690634ce38b5f90602401602060405180830381865afa1580156110c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e69190617c53565b8480546110f290617cf0565b80601f016020809104026020016040519081016040528092919081815260200182805461111e90617cf0565b801561116b5780601f106111405761010080835404028352916020019161116b565b820191906000526020600020905b81548152906001019060200180831161114e57829003601f168201915b5050505050945083805461117e90617cf0565b80601f01602080910402602001604051908101604052809291908181526020018280546111aa90617cf0565b80156111f75780601f106111cc576101008083540402835291602001916111f7565b820191906000526020600020905b8154815290600101906020018083116111da57829003601f168201915b50505050509350955095509550955095505091939590929450565b600061121c61633b565b600060fb6001600160a01b031685858560405160200161123e93929190617d24565b60408051601f198184030181529082905261125891617d72565b600060405180830381855afa9150503d8060008114611293576040519150601f19603f3d011682016040523d82523d6000602084013e611298565b606091505b50909695505050505050565b600060018060008282546112b89190617c40565b909155505060015460006112ca615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015611310573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113349190617c53565b6001600160a01b038116600090815260036020819052604090912001549091501561139d5760405162461bcd60e51b815260206004820152601960248201527856616c696461746f722067726f7570206e6f7420656d70747960381b6044820152606401610b80565b6113a9818787876163a9565b92505060015481146113cd5760405162461bcd60e51b8152600401610b8090617c70565b509392505050565b606080600080600060046000876001600160a01b03166001600160a01b031681526020019081526020016000206004019050600081600101546001600160401b03811115611425576114256176ea565b60405190808252806020026020018201604052801561144e578160200160208202803683370190505b509050600082600101546001600160401b0381111561146f5761146f6176ea565b604051908082528060200260200182016040528015611498578160200160208202803683370190505b50905060005b83600101548110156115505783546000906114b990836161ed565b60008181526002870160205260409020548551919250908590849081106114e2576114e2617d8e565b602090810291909101810191909152600082815260028701909152604090206001015483516001600160a01b039091169084908490811061152557611525617d8e565b6001600160a01b0390921660209283029190910190910152506115498160016161ed565b905061149e565b506003830154925491989097509195509350915050565b600061157282611a67565b6115b45760405162461bcd60e51b815260206004820152601360248201527204e6f742076616c696461746f722067726f757606c1b6044820152606401610b80565b506001600160a01b03166000908152600360208190526040909120015490565b60006018602160991b013b63ffffffff1615611660576115f26161f9565b6001600160a01b0316633b1eb4bf836040518263ffffffff1660e01b815260040161161f91815260200190565b602060405180830381865afa15801561163c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f399190617da4565b610f398261166c614760565b6167c8565b606060058054806020026020016040519081016040528092919081815260200182805480156116c957602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116ab575b5050505050905090565b60006116dd61633b565b6060600060f46001600160a01b0316846040516020016116fd9190617d72565b60408051601f198184030181529082905261171791617d72565b600060405180830381855afa9150503d8060008114611752576040519150601f19603f3d011682016040523d82523d6000602084013e611757565b606091505b5092509050806117cf5760405162461bcd60e51b815260206004820152603860248201527f6572726f722063616c6c696e672067657456657269666965645365616c42697460448201527f6d617046726f6d48656164657220707265636f6d70696c6500000000000000006064820152608401610b80565b6117da826000616802565b949350505050565b604051674163636f756e747360c01b602082015260009060280160408051601f1981840301815290829052805160209091012060025463dcf0aaed60e01b8352600483018290529091339161010090046001600160a01b03169063dcf0aaed90602401602060405180830381865afa158015611862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118869190617c53565b6001600160a01b0316146118d75760405162461bcd60e51b81526020600482015260186024820152771bdb9b1e481c9959da5cdd195c99590818dbdb9d1c9858dd60421b6044820152606401610b80565b6118e0866157ba565b6118fc5760405162461bcd60e51b8152600401610b8090617cc7565b600060046000886001600160a01b03166001600160a01b03168152602001908152602001600020905061196781888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061685f92505050565b6119b35760405162461bcd60e51b815260206004820152601f60248201527f4572726f72207570646174696e67204543445341207075626c6963206b6579006044820152606401610b80565b5060019695505050505050565b6000806119cb615ea0565b6040516393c5c48760e01b81526001600160a01b03858116600483015291909116906393c5c48790602401602060405180830381865afa158015611a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a379190617c53565b9050611a42816157ba565b611a5e5760405162461bcd60e51b8152600401610b8090617cc7565b610c7281610da4565b6001600160a01b031660009081526003602052604090205460ff1690565b6000611a8f61696b565b6009805484141580611aa5575080600101548314155b611af15760405162461bcd60e51b815260206004820152601e60248201527f47726f757020726571756972656d656e7473206e6f74206368616e67656400006044820152606401610b80565b60408051808201825285815260209081018590526009869055600a85905581518681529081018590527f999f7ee1917e6d7ea08360edfe9250cda3eda859c38dcb71a92623665de64dd491015b60405180910390a15060019392505050565b6000611b5a61633b565b604080516020810185905290810183905260609060009060fa90830160408051601f1981840301815290829052611b9091617d72565b600060405180830381855afa9150503d8060008114611bcb576040519150601f19603f3d011682016040523d82523d6000602084013e611bd0565b606091505b509250905080611c415760405162461bcd60e51b815260206004820152603660248201527f6572726f722063616c6c696e672076616c696461746f725369676e65724164646044820152757265737346726f6d53657420707265636f6d70696c6560501b6064820152608401610b80565b611c4c8260006169c5565b95945050505050565b60006001806000828254611c699190617c40565b9091555050600154611c7b8484614102565b91506001548114611c9e5760405162461bcd60e51b8152600401610b8090617c70565b5092915050565b60006001806000828254611cb99190617c40565b90915550506001546000611ccb615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015611d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d359190617c53565b9050611d4081611a67565b611d5c5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0381166000908152600360208190526040909120015415611dc25760405162461bcd60e51b815260206004820152601960248201527856616c696461746f722067726f7570206e6f7420656d70747960381b6044820152606401610b80565b6001600160a01b0381166000908152600360205260409020600801805460011015611e745742611e1d60096001015483600181548110611e0457611e04617d8e565b90600052602060002001546161ed90919063ffffffff16565b10611e745760405162461bcd60e51b815260206004820152602160248201527f4861736e2774206265656e20656d70747920666f72206c6f6e6720656e6f75676044820152600d60fb1b6064820152608401610b80565b6001600160a01b03821660009081526003602081905260408220805460ff19168155600181018390556002810183905590810182905560058101829055600681018290556007810182905590611ecd6008830182617561565b50600060098201819055600a8201819055600b8201819055600c8201819055600d90910155611efe600583876169d1565b6040516001600160a01b038316907fae7e034b0748a10a219b46074b20977a9170bf4027b156c797093773619a866990600090a26001935050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b6000611f6361633b565b6060600060f66001600160a01b031684604051602001611f839190617d72565b60408051601f1981840301815290829052611f9d91617d72565b600060405180830381855afa9150503d8060008114611fd8576040519150601f19603f3d011682016040523d82523d6000602084013e611fdd565b606091505b5092509050806117cf5760405162461bcd60e51b815260206004820152602360248201527f6572726f722063616c6c696e67206861736848656164657220707265636f6d70604482015262696c6560e81b6064820152608401610b80565b600180600082825461204d9190617c40565b909155505060015461205d61696b565b601082905560015481146120835760405162461bcd60e51b8152600401610b8090617c70565b5050565b61208f61696b565b600f5481036120ec5760405162461bcd60e51b815260206004820152602360248201527f636f6d6d697373696f6e207570646174652064656c6179206e6f74206368616e60448201526219d95960ea1b6064820152608401610b80565b600f8190556040518181527ff2da07d08fd8dc9c5dcf87ad6f540e306f884a47dd8de14b718a4d5395f1ca9b9060200160405180910390a150565b60606000826001600160401b03811115612143576121436176ea565b60405190808252806020026020018201604052801561216c578160200160208202803683370190505b50905060005b838110156113cd576121a485858381811061218f5761218f617d8e565b90506020020160208101906106349190617614565b8282815181106121b6576121b6617d8e565b60209081029190910101526121cc8160016161ed565b9050612172565b6121db61696b565b6121e56000616b4b565b565b60006121f161633b565b6121fa43614a76565b905090565b600061220961696b565b600780548414158061221f575080600101548314155b6122765760405162461bcd60e51b815260206004820152602260248201527f56616c696461746f7220726571756972656d656e7473206e6f74206368616e67604482015261195960f21b6064820152608401610b80565b60408051808201825285815260209081018590526007869055600885905581518681529081018590527f62d947118dd4c1f5ece7f787a9cad4e1127d14d403b71133e95792b473bf83899101611b3e565b60006122d1615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015612317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233b9190617c53565b905061234681611a67565b6123625760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b038116600090815260036020908152604080832081518084018352939093528051918201905283815261239d610b3b615a31565b6124045760405162461bcd60e51b815260206004820152603260248201527f566f7465722072657761726420636f6d6d697373696f6e2063616e27742062656044820152712067726561746572207468616e203130302560701b6064820152608401610b80565b604080516020810190915260125490819052815111156124365760405162461bcd60e51b8152600401610b8090617dbd565b600082600d015460000361244d5782600b01612452565b82600c015b604080516020810190915290548082528351919250036124c65760405162461bcd60e51b815260206004820152602960248201527f566f7465722072657761726420636f6d6d697373696f6e206d75737420626520604482015268191a5999995c995b9d60ba1b6064820152608401610b80565b8151600c840155600f546000906124dd9043617c40565b600d850181905560408051888152602081018390529192506001600160a01b038716917f4db5e9c155a624051fb60d23ce6897f5144b5d3ef48bfd0ee5217606ed848940910160405180910390a2505050505050565b600061253d615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015612583573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a79190617c53565b90506125b281611a67565b6125ce5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b03811660009081526003602052604090206125f56125f1615a31565b5190565b8311156126145760405162461bcd60e51b8152600401610b8090617e08565b604080516020810190915260058201549081905283036126765760405162461bcd60e51b815260206004820152601c60248201527f436f6d6d697373696f6e206d75737420626520646966666572656e74000000006044820152606401610b80565b604080516020808201835260009091528151908101909152838152516006820155600f546126a59043906161ed565b600782018190556040516001600160a01b038416917f557d39a57520d9835859d4b7eda805a7f4115a59c3a374eeed488436fc62a152916126ee91878252602082015260400190565b60405180910390a2505050565b60006018602160991b013b63ffffffff161561277a576127196161f9565b6001600160a01b031663639a84d36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612756573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa9190617da4565b6121fa616b9b565b600061278c61633b565b6060600060f76001600160a01b0316846040516020016127ac9190617d72565b60408051601f19818403018152908290526127c691617d72565b600060405180830381855afa9150503d8060008114612801576040519150601f19603f3d011682016040523d82523d6000602084013e612806565b606091505b5092509050806128725760405162461bcd60e51b815260206004820152603160248201527f6572726f722063616c6c696e6720676574426c6f636b4e756d62657246726f6d60448201527048656164657220707265636f6d70696c6560781b6064820152608401610b80565b6117da8260006169c5565b600060018060008282546128919190617c40565b909155505060015460006128a3615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa1580156128e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290d9190617c53565b9050612918816157ba565b6129345760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b038082166000908152600460205260409020600281015490911615612a455760028101546001600160a01b0390811660009081526003602052604090819020905163542424fb60e01b81526001909101600482015290831660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af41580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f89190617e4d565b15612a455760405162461bcd60e51b815260206004820152601e60248201527f486173206265656e2067726f7570206d656d62657220726563656e746c7900006044820152606401610b80565b6008546007820154600091612a5a91906161ed565b9050428110612aab5760405162461bcd60e51b815260206004820152601c60248201527f4e6f742079657420726571756972656d656e7420656e642074696d65000000006044820152606401610b80565b612ab7600684886169d1565b6001600160a01b0383166000908152600460205260408120908181612adc828261757f565b612aea60018301600061757f565b5050506002810180546001600160a01b0319169055600060038201819055600482018190556005820181905560079091018190556040516001600160a01b038516917f51407fafe7ef9bec39c65a12a4885a274190991bf1e9057fcc384fc77ff1a7f091a2600194505050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b6001600160a01b038216600090815260036020526040808220905163b1cfea4360e01b81526001909101600482015260248101839052606091907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063b1cfea4390604401600060405180830381865af4158015612bed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c159190810190617e6f565b90506000836001600160401b03811115612c3157612c316176ea565b604051908082528060200260200182016040528015612c5a578160200160208202803683370190505b5090506000612c67615ea0565b905060005b85811015612d4557816001600160a01b0316634ce38b5f858381518110612c9557612c95617d8e565b60200260200101516040518263ffffffff1660e01b8152600401612cc891906001600160a01b0391909116815260200190565b602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d099190617c53565b838281518110612d1b57612d1b617d8e565b6001600160a01b0390921660209283029190910190910152612d3e8160016161ed565b9050612c6c565b509095945050505050565b612d5861696b565b612d606161f9565b6001600160a01b0316634406d6616040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc19190617e4d565b15612e3e5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f7420757064617465206d617820766f74657220726577617264206360448201527f6f6d6d697373696f6e20647572696e672065706f63682070726f63657373696e6064820152606760f81b608482015260a401610b80565b604080516020808201835260009091528151908101909152818152612e64610b3b615a31565b612ecf5760405162461bcd60e51b815260206004820152603660248201527f4d617820766f7465722072657761726420636f6d6d697373696f6e2063616e27604482015275742062652067726561746572207468616e203130302560501b6064820152608401610b80565b604080516020810190915260125490819052815103612f405760405162461bcd60e51b815260206004820152602760248201527f4d617820766f7465722072657761726420636f6d6d697373696f6e206e6f742060448201526618da185b99d95960ca1b6064820152608401610b80565b60408051602081019091526012549081905281511015612f5f57436013555b80516012556040518281527f99cfb385bfbddf7c5a35a50d42eab6eef264db0850955419eb205a1a89a72dab9060200160405180910390a15050565b60006001806000828254612faf9190617c40565b90915550506001546000612fc1615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302b9190617c53565b905061303681611a67565b6130705760405162461bcd60e51b815260206004820152600b60248201526a04e6f7420612067726f75760ac1b6044820152606401610b80565b613079866157ba565b6130955760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b0381811660009081526003602052604090819020905163542424fb60e01b81526001820160048201529188166024830152907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af415801561310a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312e9190617e4d565b6131765760405162461bcd60e51b815260206004820152601960248201527804e6f742061206d656d626572206f66207468652067726f757603c1b6044820152606401610b80565b60405163597c7f4b60e11b81526001820160048201526001600160a01b0380891660248301528088166044830152861660648201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063b2f8fe969060840160006040518083038186803b1580156131e257600080fd5b505af41580156131f6573d6000803e3d6000fd5b50506040516001600160a01b03808b169350851691507f38819cc49a343985b478d72f531a35b15384c398dd80fd191a14662170f895c690600090a360019350505060015481146113cd5760405162461bcd60e51b8152600401610b8090617c70565b60006121fa436115d4565b600061326e61633b565b6060600060f96001600160a01b03168460405160200161329091815260200190565b60408051601f19818403018152908290526132aa91617d72565b600060405180830381855afa9150503d80600081146132e5576040519150601f19603f3d011682016040523d82523d6000602084013e6132ea565b606091505b5092509050806128725760405162461bcd60e51b815260206004820152602e60248201527f6572726f722063616c6c696e67206e756d62657256616c696461746f7273496e60448201526d53657420707265636f6d70696c6560901b6064820152608401610b80565b60606000806000606060008061336888611a67565b6133845760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b038816600090815260036020526040908190209051637f1e3d4760e11b81526001820160048201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063fe3c7a8e90602401600060405180830381865af41580156133ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526134179190810190617e6f565b60408051602081019091526005830154908190526040805160208101909152600684015490819052600784015460408051602081019091526009860154908190526008860190600a8701548254604080516020808402820181019092528281529185918301828280156134a957602002820191906000526020600020905b815481526020019060010190808311613495575b50505050509250975097509750975097509750975050919395979092949650565b60025460ff161561351d5760405162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a6564000000006044820152606401610b80565b6002805460ff1916600117905561353333616b4b565b61353c89613584565b6135468888611a85565b5061355186866121ff565b5061355b8261484f565b506135668135612087565b61356f84615645565b506135798361203b565b505050505050505050565b61358c61696b565b6001600160a01b0381166135e25760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f7420726567697374657220746865206e756c6c20616464726573736044820152606401610b80565b60028054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b90600090a250565b600061363e615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a89190617c53565b90506136b381611a67565b6136cf5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b03811660009081526003602052604090206136ef6161f9565b6001600160a01b0316634406d6616040518163ffffffff1660e01b8152600401602060405180830381865afa15801561372c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137509190617e4d565b156137c35760405162461bcd60e51b815260206004820152603d60248201527f43616e6e6f742075706461746520766f7465722072657761726420636f6d6d6960448201527f7373696f6e20647572696e672065706f63682070726f63657373696e670000006064820152608401610b80565b80600d01546000036138285760405162461bcd60e51b815260206004820152602860248201527f4e6f20766f7465722072657761726420636f6d6d697373696f6e20757064617460448201526719481c5d595d595960c21b6064820152608401610b80565b4381600d015411156138935760405162461bcd60e51b815260206004820152602e60248201527f43616e2774206170706c7920766f7465722072657761726420636f6d6d69737360448201526d1a5bdb881d5c19185d19481e595d60921b6064820152608401610b80565b60135481600d01541161391a5760405162461bcd60e51b815260206004820152604360248201527f566f7465722072657761726420636f6d6d697373696f6e20636170207265647560448201527f6365642073696e6365207175657565643b2072652d71756575652072657175696064820152621c995960ea1b608482015260a401610b80565b604080516020808201835260125482528251908101909252600c8301549182905251101561395a5760405162461bcd60e51b8152600401610b8090617dbd565b600c81018054600b830181905560408051602080820183526000918290528251808201845282905293819055600d85015580519283019052908190526001600160a01b038316907f4fdad274bc1c02c1dbcb516958124a63015f21accccf151f1440d5d255c5a5c6905b60405190815260200160405180910390a25050565b600060018060008282546139ed9190617c40565b909155505060015460006139ff615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a699190617c53565b9050613a74816157ba565b613a905760405162461bcd60e51b8152600401610b8090617cc7565b613a9984611a67565b613ab55760405162461bcd60e51b8152600401610b8090617c98565b613abe81613f6b565b613b165760405162461bcd60e51b815260206004820152602360248201527f56616c696461746f7220646f65736e2774206d65657420726571756972656d656044820152626e747360e81b6064820152608401610b80565b613b1f84613f6b565b613b6b5760405162461bcd60e51b815260206004820152601f60248201527f47726f757020646f65736e2774206d65657420726571756972656d656e7473006044820152606401610b80565b6001600160a01b038082166000908152600460205260409020600281015490911615613b9d57613b9b8183616c83565b505b6002810180546001600160a01b0319166001600160a01b0387811691821790925560405190918416907f91ef92227057e201e406c3451698dd780fe7672ad74328591c88d281af31581d90600090a36001935050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b6001806000828254613c259190617c40565b90915550506001546000613c37615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613c7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ca19190617c53565b9050613cac81611a67565b613cc85760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0381166000908152600360205260409020601054600a820154613cf1916161ed565b421015613d665760405162461bcd60e51b815260206004820152603b60248201527f607265736574536c617368696e674d756c7469706c696572602063616c6c656460448201527f206265666f7265207265736574506572696f64206578706972656400000000006064820152608401610b80565b613d6e615a31565b51600990910155506001548114613d975760405162461bcd60e51b8152600401610b8090617c70565b50565b6000613da5826157ba565b613dc15760405162461bcd60e51b8152600401610b8090617cc7565b506001600160a01b039081166000908152600460205260409020600201541690565b6001806000828254613df59190617c40565b9091555050600154613e05616d94565b6040516357601c5d60e01b81523360048201526001600160a01b0391909116906357601c5d90602401602060405180830381865afa158015613e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6f9190617e4d565b613ebb5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c6044820152606401610b80565b613ec482611a67565b613ee05760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0382166000908152600360209081526040918290208251918201909252600982015490819052613f3d90613f1f906002905b90616dcd565b60408051602080820183526000909152815190810190915290815290565b51600982015542600a9091015560015481146120835760405162461bcd60e51b8152600401610b8090617c70565b600080613f76616d94565b6040516330ec70f560e01b81526001600160a01b03858116600483015291909116906330ec70f590602401602060405180830381865afa158015613fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe29190617da4565b9050613fed83614678565b613ff882600a6161ed565b10159392505050565b600060018060008282546140159190617c40565b90915550506001546000614027615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa15801561406d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140919190617c53565b6001600160a01b038116600090815260036020819052604090912001549091506140f55760405162461bcd60e51b815260206004820152601560248201527456616c696461746f722067726f757020656d70747960581b6044820152606401610b80565b610d7a81856000806163a9565b600060018060008282546141169190617c40565b90915550506001546000614128615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa15801561416e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141929190617c53565b905061419d81616dd9565b6141a6816157ba565b1580156141b957506141b781611a67565b155b6141fa5760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b6044820152606401610b80565b6000614204616d94565b6040516330ec70f560e01b81526001600160a01b03848116600483015291909116906330ec70f590602401602060405180830381865afa15801561424c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142709190617da4565b6007549091508110156142b95760405162461bcd60e51b815260206004820152601160248201527011195c1bdcda5d081d1bdbc81cdb585b1b607a1b6044820152606401610b80565b6001600160a01b0382166000908152600460205260408120906142da615ea0565b604051634ce38b5f60e01b81526001600160a01b0386811660048301529190911690634ce38b5f90602401602060405180830381865afa158015614322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143469190617c53565b905061438a8285838b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061685f92505050565b6143d65760405162461bcd60e51b815260206004820152601f60248201527f4572726f72207570646174696e67204543445341207075626c6963206b6579006044820152606401610b80565b6006805460018101825560009182527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0319166001600160a01b03871617905561442b908590616f74565b506040516001600160a01b038516907fd09501348473474a20c772c79c653e1fd7e8b437e418fe235d277d2c8885325190600090a260019550505050506001548114611c9e5760405162461bcd60e51b8152600401610b8090617c70565b60606000614495615ea0565b6006549091506000906001600160401b038111156144b5576144b56176ea565b6040519080825280602002602001820160405280156144de578160200160208202803683370190505b50905060005b8151811015611c9e57826001600160a01b0316634ce38b5f6006838154811061450f5761450f617d8e565b60009182526020909120015460405160e083901b6001600160e01b03191681526001600160a01b039091166004820152602401602060405180830381865afa15801561455f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145839190617c53565b82828151811061459557614595617d8e565b6001600160a01b03909216602092830291909101909101526145b88160016161ed565b90506144e4565b606060068054806020026020016040519081016040528092919081815260200182805480156116c9576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116116ab575050505050905090565b600061462a82611a67565b6146465760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0382166000908152600360209081526040918290208251918201909252600982015490819052610c72565b6000614683826157ba565b1561469057505060075490565b61469982611a67565b15614758576001600160a01b0382166000908152600360208190526040822001546146c6906001906171e6565b6001600160a01b03841660009081526003602052604090206008018054919250901561474b5780546000906146fc9060016161e1565b90505b80156147495742614721600960010154848481548110611e0457611e04617d8e565b106147375761473081846171e6565b9250614749565b6147428160016161e1565b90506146ff565b505b6009546117da90836171fc565b506000919050565b600061476a61633b565b604051600160f81b602082015260609060009060f89060210160408051601f198184030181529082905261479d91617d72565b600060405180830381855afa9150503d80600081146147d8576040519150601f19603f3d011682016040523d82523d6000602084013e6147dd565b606091505b50925090508061483d5760405162461bcd60e51b815260206004820152602560248201527f6572726f722063616c6c696e672067657445706f636853697a6520707265636f6044820152646d70696c6560d81b6064820152608401610b80565b6148488260006169c5565b9250505090565b600061485961696b565b816000106148a95760405162461bcd60e51b815260206004820152601d60248201527f4d61782067726f75702073697a652063616e6e6f74206265207a65726f0000006044820152606401610b80565b600e5482036148fa5760405162461bcd60e51b815260206004820152601a60248201527f4d61782067726f75702073697a65206e6f74206368616e6765640000000000006044820152606401610b80565b600e8290556040518281527f603fe12c33c253a23da1680aa453dc70c3a0ee07763569bd5f602406ebd4e5d5906020015b60405180910390a1506001919050565b600180600082825461494d9190617c40565b909155505060015461495d616d94565b6040516357601c5d60e01b81523360048201526001600160a01b0391909116906357601c5d90602401602060405180830381865afa1580156149a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c79190617e4d565b614a135760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c6044820152606401610b80565b614a1c826157ba565b15614a55576001600160a01b038083166000908152600460205260409020600281015490911615614a5357614a518184616c83565b505b505b60015481146120835760405162461bcd60e51b8152600401610b8090617c70565b6000614a8061633b565b610f396003613f196002614a9e6002614a9888613264565b906171fc565b906161ed565b6001600160a01b038216600090815260036020526040808220905163b1cfea4360e01b81526001909101600482015260248101839052606091907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063b1cfea4390604401600060405180830381865af4158015614b1a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117da9190810190617e6f565b6000614b4c615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015614b92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bb69190617c53565b9050614bc181611a67565b614bdd5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0381166000908152600360205260409020614bfe81617208565b8060070154600003614c525760405162461bcd60e51b815260206004820152601b60248201527f4e6f20636f6d6d697373696f6e207570646174652071756575656400000000006044820152606401610b80565b4381600701541115614cb05760405162461bcd60e51b815260206004820152602160248201527f43616e2774206170706c7920636f6d6d697373696f6e207570646174652079656044820152601d60fa1b6064820152608401610b80565b60068101805460058301819055600091829055600783019190915560408051602081019091528190526001600160a01b038316907f815d292dbc1a08dfb3103aabb6611233dd2393903e57bdf4c5b3db91198a826c906139c4565b6001806000828254614d1d9190617c40565b90915550506001546040516b22b837b1b426b0b730b3b2b960a11b6020820152602c0160408051601f1981840301815290829052805160209091012060025463dcf0aaed60e01b8352600483018290529091339161010090046001600160a01b03169063dcf0aaed90602401602060405180830381865afa158015614da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614dca9190617c53565b6001600160a01b031614614e1b5760405162461bcd60e51b81526020600482015260186024820152771bdb9b1e481c9959da5cdd195c99590818dbdb9d1c9858dd60421b6044820152606401610b80565b614e236172cc565b6040516340c10f1960e01b8152336004820152602481018590526001600160a01b0391909116906340c10f19906044016020604051808303816000875af1158015614e72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e969190617e4d565b614a535760405162461bcd60e51b815260206004820152601c60248201527f6d696e74206661696c656420746f2065706f6368206d616e61676572000000006044820152606401610b80565b6000614eed846157ba565b614f095760405162461bcd60e51b8152600401610b8090617cc7565b614f11613259565b831115614f6c5760405162461bcd60e51b815260206004820152602360248201527f45706f63682063616e6e6f74206265206c6172676572207468616e2063757272604482015262195b9d60ea1b6064820152608401610b80565b6001600160a01b03841660009081526004602081905260409091206005810154910180549091614f9c91906161ed565b8310614fe05760405162461bcd60e51b8152602060048201526013602482015272696e646578206f7574206f6620626f756e647360681b6044820152606401610b80565b80548310801590614ff5575060008160010154115b6150375760405162461bcd60e51b8152602060048201526013602482015272696e646578206f7574206f6620626f756e647360681b6044820152606401610b80565b6000838152600282016020526040812054600180840154918714929161505c916161e1565b83546150699087906161e1565b6000878152600286016020526040812054919092149250871180156150b657508660028501600061509b8960016161ed565b81526020019081526020016000206000015411806150b65750815b905082806150c15750805b6151435760405162461bcd60e51b815260206004820152604760248201527f70726f766964656420696e64657820646f6573206e6f74206d6174636820707260448201527f6f76696465642065706f63684e756d62657220617420696e64657820696e206860648201526634b9ba37b93c9760c91b608482015260a401610b80565b50505060009283526002016020525060409020600101546001600160a01b031692915050565b60008061517461633b565b861580159061518257508415155b6151c65760405162461bcd60e51b8152602060048201526015602482015274612064656e6f6d696e61746f72206973207a65726f60581b6044820152606401610b80565b60408051602081018a905290810188905260608181018890526080820187905260a0820186905260c082018590526000918291829160fc9060e00160408051601f198184030181529082905261521b91617d72565b600060405180830381855afa9150503d8060008114615256576040519150601f19603f3d011682016040523d82523d6000602084013e61525b565b606091505b509092509050816152be5760405162461bcd60e51b815260206004820152602760248201527f6572726f722063616c6c696e67206672616374696f6e4d756c45787020707265604482015266636f6d70696c6560c81b6064820152608401610b80565b6152c98160006169c5565b93506152d68160206169c5565b939c939b50929950505050505050505050565b600060018060008282546152fd9190617c40565b90915550506001546153106125f1615a31565b83111561532f5760405162461bcd60e51b8152600401610b8090617e08565b6000615339615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa15801561537f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906153a39190617c53565b90506153ae81616dd9565b6153b7816157ba565b156154045760405162461bcd60e51b815260206004820152601f60248201527f416c726561647920726567697374657265642061732076616c696461746f72006044820152606401610b80565b61540d81611a67565b1561545a5760405162461bcd60e51b815260206004820152601b60248201527f416c726561647920726567697374657265642061732067726f757000000000006044820152606401610b80565b6000615464616d94565b6040516330ec70f560e01b81526001600160a01b03848116600483015291909116906330ec70f590602401602060405180830381865afa1580156154ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906154d09190617da4565b60095490915081101561551e5760405162461bcd60e51b8152602060048201526016602482015275139bdd08195b9bdd59da081b1bd8dad9590819dbdb1960521b6044820152606401610b80565b6001600160a01b0382166000908152600360205260409020805460ff191660011781556155638660408051602080820183526000909152815190810190915290815290565b516005820155604080518082019091528061557c615a31565b8152600060209182018190528251516009850155910151600a8301556005805460018101825591527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b0385166001600160a01b031990911681179091556040517fbf4b45570f1907a94775f8449817051a492a676918e38108bb762e991e6b58dc906156159089815260200190565b60405180910390a2600194505050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b600061564f61696b565b816000106156b05760405162461bcd60e51b815260206004820152602860248201527f4d656d6265727368697020686973746f7279206c656e6774682063616e6e6f74604482015267206265207a65726f60c01b6064820152608401610b80565b600d54820361570f5760405162461bcd60e51b815260206004820152602560248201527f4d656d6265727368697020686973746f7279206c656e677468206e6f74206368604482015264185b99d95960da1b6064820152608401610b80565b600d8290556040518281527f1c75c7fb3ee9d13d8394372d8c7cdf1702fa947faa03f6ccfa500f787b09b48a9060200161492b565b61574c61696b565b6001600160a01b0381166157b15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b80565b613d9781616b4b565b6001600160a01b038116600090815260046020526040812080548291906157e090617cf0565b9050119050919050565b60006157f461633b565b6060600060f56001600160a01b03168460405160200161581691815260200190565b60408051601f198184030181529082905261583091617d72565b600060405180830381855afa9150503d806000811461586b576040519150601f19603f3d011682016040523d82523d6000602084013e615870565b606091505b5092509050806117cf5760405162461bcd60e51b815260206004820152602c60248201527f6572726f722063616c6c696e6720676574506172656e745365616c4269746d6160448201526b7020707265636f6d70696c6560a01b6064820152608401610b80565b600060018060008282546158eb9190617c40565b909155505060015460006158fd615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015615943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906159679190617c53565b9050615972816157ba565b61598e5760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b03808216600090815260046020526040902060028101549091166159fb5760405162461bcd60e51b815260206004820152601b60248201527f6465616666696c696174653a206e6f7420616666696c696174656400000000006044820152606401610b80565b615a058183616c83565b506001935050506001548114615a2d5760405162461bcd60e51b8152600401610b8090617c70565b5090565b60408051602080820183526000909152815190810190915269d3c21bcecceda1000000815290565b6040805160208101909152600081527601357c299a88ea76a58924d52ce4f26a85af186c2b9e74821115615aee5760405162461bcd60e51b815260206004820152603660248201527f63616e277420637265617465206669786964697479206e756d626572206c6172604482015275676572207468616e206d61784e65774669786564282960501b6064820152608401610b80565b604051806020016040528069d3c21bcecceda100000084615b0f9190617f20565b905292915050565b60408051602081019091526000815282511580615b3357508151155b15615b4d5750604080516020810190915260008152610f39565b815169d3c21bcecceda0ffffff1901615b67575081610f39565b825169d3c21bcecceda0ffffff1901615b81575080610f39565b600069d3c21bcecceda1000000615b9785617306565b51615ba29190617f4d565b90506000615baf85617345565b519050600069d3c21bcecceda1000000615bc886617306565b51615bd39190617f4d565b90506000615be086617345565b5190506000615bef8386617f20565b90508415615c485782615c028683617f4d565b14615c485760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c5e4c4819195d1958dd195960521b6044820152606401610b80565b6000615c5e69d3c21bcecceda100000083617f20565b90508115615cc85769d3c21bcecceda1000000615c7b8383617f4d565b14615cc85760405162461bcd60e51b815260206004820152601f60248201527f6f766572666c6f772078317931202a20666978656431206465746563746564006044820152606401610b80565b9050806000615cd78587617f20565b90508515615d305784615cea8783617f4d565b14615d305760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c9e4c4819195d1958dd195960521b6044820152606401610b80565b6000615d3c8589617f20565b90508715615d955784615d4f8983617f4d565b14615d955760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c5e4c8819195d1958dd195960521b6044820152606401610b80565b615da464e8d4a5100088617f4d565b9650615db564e8d4a5100086617f4d565b94506000615dc38689617f20565b90508715615e1c5785615dd68983617f4d565b14615e1c5760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c9e4c8819195d1958dd195960521b6044820152606401610b80565b6040805160208082018352878252825190810190925284825290615e41908290617390565b9050615e5b81604051806020016040528086815250617390565b9050615e7581604051806020016040528085815250617390565b9d9c50505050505050505050505050565b8051600090610f399069d3c21bcecceda100000090617f4d565b600254604051674163636f756e747360c01b602082015260009161010090046001600160a01b03169063dcf0aaed906028015b604051602081830303815290604052805190602001206040518263ffffffff1660e01b8152600401615f0791815260200190565b602060405180830381865afa158015615f24573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa9190617c53565b6001600160a01b0380831660008181526003602090815260408083208686168452600490925282206002015491939092911614615fc15760405162461bcd60e51b815260206004820152601760248201527604e6f7420616666696c696174656420746f2067726f757604c1b6044820152606401610b80565b60405163542424fb60e01b81526001820160048201526001600160a01b03841660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af4158015616022573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906160469190617e4d565b61608e5760405162461bcd60e51b815260206004820152601960248201527804e6f742061206d656d626572206f66207468652067726f757603c1b6044820152606401610b80565b60405163716062b560e11b81526001820160048201526001600160a01b03841660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063e2c0c56a9060440160006040518083038186803b1580156160ea57600080fd5b505af41580156160fe573d6000803e3d6000fd5b505050506003810154600081900361617657616118617410565b60405163a8e4587160e01b81526001600160a01b038781166004830152919091169063a8e4587190602401600060405180830381600087803b15801561615d57600080fd5b505af1158015616171573d6000803e3d6000fd5b505050505b616181846000616f74565b50616196856161918360016161ed565b617447565b836001600160a01b0316856001600160a01b03167fc7666a52a66ff601ff7c0d4d6efddc9ac20a34792f6aa003d1804c9d4d5baa5760405160405180910390a3506001949350505050565b6000610c728284617f61565b6000610c728284617c40565b6002546040516b22b837b1b426b0b730b3b2b960a11b602082015260009161010090046001600160a01b03169063dcf0aaed90602c01615ed3565b600061623e61633b565b6060600060fa6001600160a01b03168443604051602001616269929190918252602082015260400190565b60408051601f198184030181529082905261628391617d72565b600060405180830381855afa9150503d80600081146162be576040519150601f19603f3d011682016040523d82523d6000602084013e6162c3565b606091505b5092509050806128725760405162461bcd60e51b815260206004820152603d60248201527f6572726f722063616c6c696e672076616c696461746f725369676e657241646460448201527f7265737346726f6d43757272656e7453657420707265636f6d70696c650000006064820152608401610b80565b6018602160991b013b63ffffffff16156121e55760405162461bcd60e51b815260206004820152602960248201527f54686973206d6574686f64206973206e6f206c6f6e67657220737570706f727460448201526832b21034b71026191760b91b6064820152608401610b80565b60006163b485611a67565b80156163c457506163c4846157ba565b6164105760405162461bcd60e51b815260206004820152601760248201527f4e6f742076616c696461746f7220616e642067726f75700000000000000000006044820152606401610b80565b6001600160a01b0385166000908152600360208190526040909120600e54918101549091116164815760405162461bcd60e51b815260206004820152601f60248201527f67726f757020776f756c6420657863656564206d6178696d756d2073697a65006044820152606401610b80565b6001600160a01b038581166000908152600460205260409020600201548116908716146164ea5760405162461bcd60e51b815260206004820152601760248201527604e6f7420616666696c696174656420746f2067726f757604c1b6044820152606401610b80565b60405163542424fb60e01b81526001820160048201526001600160a01b03861660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af415801561654b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061656f9190617e4d565b156165af5760405162461bcd60e51b815260206004820152601060248201526f0416c726561647920696e2067726f75760841b6044820152606401610b80565b60038101546000906165c29060016161ed565b6040516326afac4960e01b81526001840160048201526001600160a01b03881660248201529091507308a4b5bc1b5adef0a283c8f0185ded6169f0bd29906326afac499060440160006040518083038186803b15801561662157600080fd5b505af4158015616635573d6000803e3d6000fd5b5050505061664287613f6b565b61668e5760405162461bcd60e51b815260206004820152601a60248201527f47726f757020726571756972656d656e7473206e6f74206d65740000000000006044820152606401610b80565b61669786613f6b565b6166e35760405162461bcd60e51b815260206004820152601e60248201527f56616c696461746f7220726571756972656d656e7473206e6f74206d657400006044820152606401610b80565b80600103616761576166f3617410565b60405163a18fb2db60e01b81526001600160a01b03898116600483015287811660248301528681166044830152919091169063a18fb2db90606401600060405180830381600087803b15801561674857600080fd5b505af115801561675c573d6000803e3d6000fd5b505050505b61676b8688616f74565b5061677b876161918360016161e1565b856001600160a01b0316876001600160a01b03167fbdf7e616a6943f81e07a7984c9d4c00197dc2f481486ce4ffa6af52a113974ad60405160405180910390a35060019695505050505050565b6000806167d58385617f4d565b90506167e18385617f74565b6000036167ef579050610f39565b6167fa8160016161ed565b915050610f39565b600061680f8260206161ed565b835110156168565760405162461bcd60e51b8152602060048201526014602482015273736c6963696e67206f7574206f662072616e676560601b6044820152606401610b80565b50016020015190565b600081516040146168b25760405162461bcd60e51b815260206004820152601d60248201527f57726f6e67204543445341207075626c6963206b6579206c656e6774680000006044820152606401610b80565b815160208301206001600160a01b038481169116146169135760405162461bcd60e51b815260206004820152601f60248201527f4543445341206b657920646f6573206e6f74206d61746368207369676e6572006044820152606401610b80565b8461691e8382617fd6565b50836001600160a01b03167f213377eec2c15b21fa7abcbb0cb87a67e893cdb94a2564aa4bb4d380869473c8836040516169589190618095565b60405180910390a2506001949350505050565b6000546001600160a01b031633146121e55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b80565b6000610c728383616802565b825481108015616a0f5750816001600160a01b03168382815481106169f8576169f8617d8e565b6000918252602090912001546001600160a01b0316145b616a655760405162461bcd60e51b815260206004820152602160248201527f64656c657465456c656d656e743a20696e646578206f7574206f662072616e676044820152606560f81b6064820152608401610b80565b8254600090616a759060016161e1565b9050838181548110616a8957616a89617d8e565b9060005260206000200160009054906101000a90046001600160a01b0316848381548110616ab957616ab9617d8e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838181548110616af957616af9617d8e565b600091825260209091200180546001600160a01b03191690558354849080616b2357616b236180a8565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000616ba561633b565b6040805143602082015260609160009160f9910160408051601f1981840301815290829052616bd391617d72565b600060405180830381855afa9150503d8060008114616c0e576040519150601f19603f3d011682016040523d82523d6000602084013e616c13565b606091505b50925090508061483d5760405162461bcd60e51b815260206004820152603560248201527f6572726f722063616c6c696e67206e756d62657256616c696461746f7273496e60448201527443757272656e7453657420707265636f6d70696c6560581b6064820152608401610b80565b6000616c8e826174f9565b60028301546001600160a01b0390811660008181526003602052604090819020905163542424fb60e01b8152600182016004820152928516602484015290917308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af4158015616d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616d2d9190617e4d565b15616d3e57616d3c8285615f48565b505b6002850180546001600160a01b03191690556040516001600160a01b0383811691908616907f71815121f0622b31a3e7270eb28acb9fd10825ff418c9a18591f617bb8a31a6c90600090a3506001949350505050565b60025460405169131bd8dad95911dbdb1960b21b602082015260009161010090046001600160a01b03169063dcf0aaed90602a01615ed3565b6000610c728284617f4d565b616de1617410565b60405163cb08c99360e01b81526001600160a01b038381166004830152919091169063cb08c993906024016020604051808303816000875af1158015616e2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616e4f9190617e4d565b15616eb35760405162461bcd60e51b815260206004820152602e60248201527f43616e6e6f7420766f746520666f72206d6f7265207468616e206d6178206e7560448201526d6d626572206f662067726f75707360901b6064820152608401610b80565b616ebb616d94565b6040516315952ae760e01b81526001600160a01b03838116600483015291909116906315952ae790602401602060405180830381865afa158015616f03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616f279190617da4565b15613d975760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f742064656c656761746520676f7665726e616e636520706f7765726044820152606401610b80565b6001600160a01b038216600090815260046020819052604082200181616f98613259565b905060008260010154600014616fd057616fcb616fc3600185600101546161e190919063ffffffff16565b8454906161ed565b616fd3565b60005b905060008360010154118015616ff057506001600160a01b038516155b15616ffc574260038401555b6000836001015411801561701f5750600081815260028401602052604090205482145b15617079576040805180820182529283526001600160a01b03868116602080860191825260009485526002969096019095529120915182559151600191820180546001600160a01b03191691909316179091559050610f39565b60008360010154600014617097576170928260016161ed565b61709a565b60005b6040805180820182528581526001600160a01b038981166020808401918252600086815260028b0190915293909320915182559151600191820180546001600160a01b0319169190931617909155600d5490860154919250111561711157600184810154617107916161ed565b60018501556119b3565b600d5484600101540361715857835460009081526002850160205260408120908155600190810180546001600160a01b03191690558454617151916161ed565b84556119b3565b8354600090815260028501602081905260408220828155600190810180546001600160a01b03191690558654919291617190916161ed565b815260208101919091526040016000908120908155600190810180546001600160a01b0319169055848101546171c5916161e1565b600185015583546171d79060026161ed565b84555060019695505050505050565b60008183116171f55781610c72565b5090919050565b6000610c728284617f20565b604051637f1e3d4760e11b81526001820160048201526000907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063fe3c7a8e90602401600060405180830381865af415801561725d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526172859190810190617e6f565b905060005b81518110156172c7576172b58282815181106172a8576172a8617d8e565b60200260200101516174f9565b806172bf816180be565b91505061728a565b505050565b6002546040516a29ba30b13632aa37b5b2b760a91b602082015260009161010090046001600160a01b03169063dcf0aaed90602b01615ed3565b604080516020810190915260008152604051806020016040528069d3c21bcecceda100000080856000015161733b9190617f4d565b615b0f9190617f20565b604080516020810190915260008152604051806020016040528069d3c21bcecceda100000080856000015161737a9190617f4d565b6173849190617f20565b8451615b0f9190617f61565b604080516020810190915260008152815183516000916173af91617c40565b84519091508110156173fb5760405162461bcd60e51b8152602060048201526015602482015274185919081bdd995c999b1bddc819195d1958dd1959605a1b6044820152606401610b80565b60408051602081019091529081529392505050565b6002546040516722b632b1ba34b7b760c11b602082015260009161010090046001600160a01b03169063dcf0aaed90602801615ed3565b6001600160a01b03821660009081526003602052604090206008018054820361748457805460018101825560008281526020902042910155505050565b80548210156174b157428183815481106174a0576174a0617d8e565b600091825260209091200155505050565b60405162461bcd60e51b815260206004820152601d60248201527f556e61626c6520746f207570646174652073697a6520686973746f72790000006044820152606401610b80565b6175016161f9565b604051635915e07760e01b81526001600160a01b0383811660048301529190911690635915e07790602401600060405180830381600087803b15801561754657600080fd5b505af115801561755a573d6000803e3d6000fd5b5050505050565b5080546000825590600052602060002090810190613d9791906175b5565b50805461758b90617cf0565b6000825580601f1061759b575050565b601f016020900490600052602060002090810190613d9791905b5b80821115615a2d57600081556001016175b6565b6001600160a01b0381168114613d9757600080fd5b6000806000606084860312156175f457600080fd5b83356175ff816175ca565b95602085013595506040909401359392505050565b60006020828403121561762657600080fd5b8135610c72816175ca565b60006020828403121561764357600080fd5b5035919050565b60005b8381101561766557818101518382015260200161764d565b50506000910152565b6000815180845261768681602086016020860161764a565b601f01601f19169290920160200192915050565b60a0815260006176ad60a083018861766e565b82810360208401526176bf818861766e565b6001600160a01b03968716604085015260608401959095525050921660809092019190915292915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715617728576177286176ea565b604052919050565b600082601f83011261774157600080fd5b81356001600160401b0381111561775a5761775a6176ea565b61776d601f8201601f1916602001617700565b81815284602083860101111561778257600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156177b457600080fd5b83356177bf816175ca565b925060208401356001600160401b03808211156177db57600080fd5b6177e787838801617730565b935060408601359150808211156177fd57600080fd5b5061780a86828701617730565b9150509250925092565b60008060006060848603121561782957600080fd5b8335617834816175ca565b92506020840135617844816175ca565b91506040840135617854816175ca565b809150509250925092565b600081518084526020808501945080840160005b8381101561788f57815187529582019590820190600101617873565b509495945050505050565b600081518084526020808501945080840160005b8381101561788f5781516001600160a01b0316875295820195908201906001016178ae565b6080815260006178e6608083018761785f565b82810360208401526178f8818761789a565b604084019590955250506060015292915050565b602081526000610c72602083018461789a565b60006020828403121561793157600080fd5b81356001600160401b0381111561794757600080fd5b6117da84828501617730565b60008083601f84011261796557600080fd5b5081356001600160401b0381111561797c57600080fd5b60208301915083602082850101111561799457600080fd5b9250929050565b600080600080606085870312156179b157600080fd5b84356179bc816175ca565b935060208501356179cc816175ca565b925060408501356001600160401b038111156179e757600080fd5b6179f387828801617953565b95989497509550505050565b60008060408385031215617a1257600080fd5b50508035926020909101359150565b60008060208385031215617a3457600080fd5b82356001600160401b03811115617a4a57600080fd5b617a5685828601617953565b90969095509350505050565b60008060208385031215617a7557600080fd5b82356001600160401b0380821115617a8c57600080fd5b818501915085601f830112617aa057600080fd5b813581811115617aaf57600080fd5b8660208260051b8501011115617ac457600080fd5b60209290920196919550909350505050565b602081526000610c72602083018461785f565b60008060408385031215617afc57600080fd5b8235617b07816175ca565b946020939093013593505050565b60e081526000617b2860e083018a61789a565b8860208401528760408401528660608401528281036080840152617b4c818761785f565b60a0840195909552505060c0015295945050505050565b6000806000806000806000806000898b03610120811215617b8357600080fd5b8a35617b8e816175ca565b995060208b810135995060408c0135985060608c0135975060808c0135965060a08c0135955060c08c0135945060e08c0135935060ff1982011215617bd257600080fd5b506101008a0190509295985092959850929598565b60008060008060008060c08789031215617c0057600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610f3957610f39617c2a565b600060208284031215617c6557600080fd5b8151610c72816175ca565b6020808252600e908201526d1c99595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527404e6f7420612076616c696461746f722067726f757605c1b604082015260600190565b6020808252600f908201526e2737ba1030903b30b634b230ba37b960891b604082015260600190565b600181811c90821680617d0457607f821691505b602082108103610d9e57634e487b7160e01b600052602260045260246000fd5b6bffffffffffffffffffffffff198460601b16815260008351617d4e81601485016020880161764a565b835190830190617d6581601484016020880161764a565b0160140195945050505050565b60008251617d8481846020870161764a565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215617db657600080fd5b5051919050565b6020808252602b908201527f566f7465722072657761726420636f6d6d697373696f6e20657863656564732060408201526a1b585e08185b1b1bddd95960aa1b606082015260800190565b60208082526025908201527f436f6d6d697373696f6e2063616e27742062652067726561746572207468616e604082015264203130302560d81b606082015260800190565b600060208284031215617e5f57600080fd5b81518015158114610c7257600080fd5b60006020808385031215617e8257600080fd5b82516001600160401b0380821115617e9957600080fd5b818501915085601f830112617ead57600080fd5b815181811115617ebf57617ebf6176ea565b8060051b9150617ed0848301617700565b8181529183018401918481019088841115617eea57600080fd5b938501935b83851015617f145784519250617f04836175ca565b8282529385019390850190617eef565b98975050505050505050565b8082028115828204841417610f3957610f39617c2a565b634e487b7160e01b600052601260045260246000fd5b600082617f5c57617f5c617f37565b500490565b81810381811115610f3957610f39617c2a565b600082617f8357617f83617f37565b500690565b601f8211156172c757600081815260208120601f850160051c81016020861015617faf5750805b601f850160051c820191505b81811015617fce57828155600101617fbb565b505050505050565b81516001600160401b03811115617fef57617fef6176ea565b61800381617ffd8454617cf0565b84617f88565b602080601f83116001811461803857600084156180205750858301515b600019600386901b1c1916600185901b178555617fce565b600085815260208120601f198616915b8281101561806757888601518255948401946001909101908401618048565b50858210156180855787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000610c72602083018461766e565b634e487b7160e01b600052603160045260246000fd5b6000600182016180d0576180d0617c2a565b506001019056fea2646970667358221220184590790187f92f0db5ee302e283f93ff6ff08d611d8c8a9df1b8e932d1db4664736f6c63430008130033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{"contracts-0.8/common/linkedlists/AddressLinkedList.sol":{"AddressLinkedList":"0x08a4b5bc1b5adef0a283c8f0185ded6169f0bd29"}},"metadata":{"appendCBOR":true,"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@celo-contracts/=contracts/","@celo-contracts-8/=contracts-0.8/","@test-sol/=test-sol/","@migrations-sol/=migrations_sol/","@lib/=lib/","celo-foundry/=lib/celo-foundry/src/","celo-foundry-8/=lib/celo-foundry-8/src/","ds-test/=lib/celo-foundry/lib/forge-std/lib/ds-test/src/","forge-std/=lib/celo-foundry/lib/forge-std/src/","forge-std-8/=lib/celo-foundry-8/lib/forge-std/src/","@mento-core/=lib/mento-core/","openzeppelin-solidity/=lib/openzeppelin-contracts/","@openzeppelin/contracts8/=lib/openzeppelin-contracts8/contracts/","@summa-tx/memview.sol/=lib/memview.sol/","solidity-bytes-utils/=lib/solidity-bytes-utils/","solidity-bytes-utils-8/=lib/solidity-bytes-utils-8/","erc4626-tests/=lib/openzeppelin-contracts8/lib/erc4626-tests/","mento-core/=lib/mento-core/contracts/","openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/","openzeppelin-contracts8/=lib/openzeppelin-contracts8/","openzeppelin/=lib/openzeppelin-contracts8/contracts/"],"viaIR":false},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.19+commit.7dd6d404","is_verified_via_verifier_alliance":false,"verified_at":"2026-06-16T11:49:49.496221Z","implementations":[],"proxy_type":null,"external_libraries":[{"name":"contracts-0.8/common/linkedlists/AddressLinkedList.sol:AddressLinkedList","address_hash":"0x08a4B5bc1b5aDef0a283C8f0185dEd6169F0Bd29"}],"creation_bytecode":"0x60806040523480156200001157600080fd5b50604051620081f8380380620081f88339810160408190526200003491620000b0565b80620000403362000060565b600180558062000058576002805460ff191660011790555b5050620000db565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215620000c357600080fd5b81518015158114620000d457600080fd5b9392505050565b61810d80620000eb6000396000f3fe608060405234801561001057600080fd5b50600436106104cc5760003560e01c80638b16b1c611610283578063caf3c4261161015c578063e7f03766116100ce578063ee09831011610092578063ee09831014610a97578063eff2ea3f14610aaa578063f2fde38b14610abd578063facd743b14610ad0578063fae8db0a14610ae3578063fffdfccb14610af657600080fd5b8063e7f0376614610a4d578063ea4208ac14610a55578063eb17c1fe14610a68578063eb1d0b4214610a71578063ec68307214610a8457600080fd5b8063df4da46111610120578063df4da461146109f0578063e0e3ffe6146109f8578063e1497ff714610a01578063e33301aa14610a14578063e50e652d14610a27578063e5880d9a14610a3a57600080fd5b8063caf3c426146109a7578063d55dcbcf146109ba578063d93ab5ad146109c2578063dba94fcd146109ca578063dcff4cf6146109dd57600080fd5b8063b591d3a5116101f5578063bd9e9d94116101b9578063bd9e9d9414610947578063c10c96ef14610955578063c22d3bba14610960578063c54c1cd414610973578063c580514014610986578063ca6d56dc1461099457600080fd5b8063b591d3a514610909578063b6885a181461091c578063b8f9394314610924578063b915f5301461092c578063bb0f1fa51461093457600080fd5b80639a7b3be7116102475780639a7b3be71461089a5780639b2b592f146108a25780639b9d5161146108b5578063a09f7f55146108db578063a91ee0dc146108ee578063b16f3f7b1461090157600080fd5b80638b16b1c61461083d5780638da5cb5b146108505780638dd31e391461086157806397f742bf14610874578063988dcd1f1461088757600080fd5b806351b52225116103b55780636fa4764711610327578063789c9f3d116102eb578063789c9f3d146107db5780637b103999146107e4578063849a5205146107fc57806386d81a5a1461080f57806387ee8a0f146108225780638a8836261461082a57600080fd5b80636fa476471461077c5780637044775414610798578063715018a6146107b85780637385e5da146107c057806376c0a9ed146107c857600080fd5b80635d180adb116103795780635d180adb14610708578063602a9eee1461071b57806360fb822c1461072e57806367960e91146107415780636ab951a0146107545780636c620d901461076957600080fd5b806351b52225146106a057806352f13a4e146106b357806354255be0146106c65780635779e93d146106ec5780635a61d15b146106f557600080fd5b80633173b8db1161044e5780633f270898116104125780633f2708981461064c57806343d96699146106615780634b2c2f44146106695780634cd76db41461067c5780634e06fd8a14610685578063517f6d331461069857600080fd5b80633173b8db146105e757806335244f51146105fa57806336407b701461061d57806339e618e8146106265780633b1eb4bf1461063957600080fd5b8063123633ea11610495578063123633ea14610562578063158ef93e146105755780631858dd2f146105825780631904bb2e146105b057806323f0ab65146105d457600080fd5b8062253a70146104d1578063087c344e146104ee5780630b1ca49a146105015780630d1312b81461052457806311fb9e841461054f575b600080fd5b6012546104db9081565b6040519081526020015b60405180910390f35b6104db6104fc3660046175df565b610afe565b61051461050f366004617614565b610c79565b60405190151581526020016104e5565b610537610532366004617614565b610da4565b6040516001600160a01b0390911681526020016104e5565b61053761055d366004617631565b610e5a565b610537610570366004617631565b610f3f565b6002546105149060ff1681565b610595610590366004617614565b610f93565b604080519384526020840192909252908201526060016104e5565b6105c36105be366004617614565b611007565b6040516104e595949392919061769a565b6105146105e236600461779f565b611212565b6105146105f5366004617814565b6112a4565b61060d610608366004617614565b6113d5565b6040516104e594939291906178d3565b6104db60105481565b6104db610634366004617614565b611567565b6104db610647366004617631565b6115d4565b610654611671565b6040516104e5919061790c565b600e546104db565b6104db61067736600461791f565b6116d3565b6104db600d5481565b61051461069336600461799b565b6117e2565b6006546104db565b6105376106ae366004617614565b6119c0565b6105146106c1366004617614565b611a67565b6040805160018082526004602083015291810191909152600060608201526080016104e5565b6104db600e5481565b6105146107033660046179ff565b611a85565b6105376107163660046179ff565b611b50565b610514610729366004617a21565b611c55565b61051461073c366004617631565b611ca5565b6104db61074f36600461791f565b611f59565b610767610762366004617631565b61203b565b005b610767610777366004617631565b612087565b600954600a545b604080519283526020830191909152016104e5565b6107ab6107a6366004617a62565b612127565b6040516104e59190617ad6565b6107676121d3565b6104db6121e7565b6105146107d63660046179ff565b6121ff565b6104db60135481565b6002546105379061010090046001600160a01b031681565b61076761080a366004617631565b6122c7565b61076761081d366004617631565b612533565b6104db6126fb565b6104db61083836600461791f565b612782565b61051461084b366004617631565b61287d565b6000546001600160a01b0316610537565b61065461086f366004617ae9565b612b77565b610767610882366004617631565b612d50565b610514610895366004617814565b612f9b565b6104db613259565b6104db6108b0366004617631565b613264565b6108c86108c3366004617614565b613353565b6040516104e59796959493929190617b15565b6107676108e9366004617b63565b6134ca565b6107676108fc366004617614565b613584565b610767613634565b610514610917366004617614565b6139d9565b600d546104db565b610767613c13565b600f546104db565b610537610942366004617614565b613d9a565b600754600854610783919082565b600754600854610783565b61076761096e366004617614565b613de3565b610514610981366004617614565b613f6b565b600954600a54610783919082565b6105146109a2366004617614565b614001565b6105146109b5366004617a21565b614102565b610654614489565b6106546145bf565b6104db6109d8366004617614565b61461f565b6104db6109eb366004617614565b614678565b6104db614760565b6104db600f5481565b610514610a0f366004617631565b61484f565b610767610a22366004617614565b61493b565b6104db610a35366004617631565b614a76565b610654610a48366004617ae9565b614aa4565b610767614b42565b610767610a63366004617631565b614d0b565b6104db60115481565b610537610a7f3660046175df565b614ee2565b610783610a92366004617be7565b615169565b610514610aa5366004617631565b6152e9565b610514610ab8366004617631565b615645565b610767610acb366004617614565b615744565b610514610ade366004617614565b6157ba565b6104db610af1366004617631565b6157ea565b6105146158d7565b6000610b09846157ba565b610b1557506000610c72565b604080516020808201835260009091528151908101909152838152610b43610b3b615a31565b518251111590565b610b895760405162461bcd60e51b815260206004820152601260248201527153636f7265206d757374206265203c3d203160701b60448201526064015b60405180910390fd5b6000610b9486610da4565b90506001600160a01b038116610bfa5760405162461bcd60e51b815260206004820152602560248201527f56616c696461746f72206e6f7420726567697374657265642077697468206120604482015264067726f75760dc1b6064820152608401610b80565b610c0386613f6b565b8015610c135750610c1381613f6b565b15610c6b576001600160a01b03811660009081526003602090815260408083208151928301909152600901548152610c5690610c50858189615a59565b90615b17565b9050610c6181615e86565b9350505050610c72565b6000925050505b9392505050565b60006001806000828254610c8d9190617c40565b90915550506001546000610c9f615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015610ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d099190617c53565b9050610d1481611a67565b8015610d245750610d24846157ba565b610d705760405162461bcd60e51b815260206004820152601a60248201527f6973206e6f742067726f757020616e642076616c696461746f720000000000006044820152606401610b80565b610d7a8185615f48565b9250506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b50919050565b600080610daf613259565b6001600160a01b038416600090815260046020819052604082206005810154939450019115610e0057610dfb610df3600184600101546161e190919063ffffffff16565b8354906161ed565b610e03565b60005b6000818152600284016020526040902054909150839003610e35578154811115610e3557610e328160016161e1565b90505b6000908152600290910160205260409020600101546001600160a01b03169392505050565b60006018602160991b013b63ffffffff16610ec35760405162461bcd60e51b815260206004820152602360248201527f54686973206d6574686f64206973206e6f7420737570706f7274656420696e2060448201526226189760e91b6064820152608401610b80565b610ecb6161f9565b6001600160a01b0316638657f615836040518263ffffffff1660e01b8152600401610ef891815260200190565b602060405180830381865afa158015610f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f399190617c53565b92915050565b60006018602160991b013b63ffffffff1615610f8a57610f5d6161f9565b6001600160a01b0316632ba47274836040518263ffffffff1660e01b8152600401610ef891815260200190565b610f3982616234565b6000806000610fa184611a67565b610fbd5760405162461bcd60e51b8152600401610b8090617c98565b5050506001600160a01b031660009081526003602090815260409182902082518083018452600b820154908190528351928301909352600c81015491829052600d01549192909190565b6060806000806000611018866157ba565b6110345760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b0386811660009081526004602090815260409182902060028101548351928301909352600381015491829052928392600184019291169061107a615ea0565b604051634ce38b5f60e01b81526001600160a01b038d811660048301529190911690634ce38b5f90602401602060405180830381865afa1580156110c2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e69190617c53565b8480546110f290617cf0565b80601f016020809104026020016040519081016040528092919081815260200182805461111e90617cf0565b801561116b5780601f106111405761010080835404028352916020019161116b565b820191906000526020600020905b81548152906001019060200180831161114e57829003601f168201915b5050505050945083805461117e90617cf0565b80601f01602080910402602001604051908101604052809291908181526020018280546111aa90617cf0565b80156111f75780601f106111cc576101008083540402835291602001916111f7565b820191906000526020600020905b8154815290600101906020018083116111da57829003601f168201915b50505050509350955095509550955095505091939590929450565b600061121c61633b565b600060fb6001600160a01b031685858560405160200161123e93929190617d24565b60408051601f198184030181529082905261125891617d72565b600060405180830381855afa9150503d8060008114611293576040519150601f19603f3d011682016040523d82523d6000602084013e611298565b606091505b50909695505050505050565b600060018060008282546112b89190617c40565b909155505060015460006112ca615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015611310573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113349190617c53565b6001600160a01b038116600090815260036020819052604090912001549091501561139d5760405162461bcd60e51b815260206004820152601960248201527856616c696461746f722067726f7570206e6f7420656d70747960381b6044820152606401610b80565b6113a9818787876163a9565b92505060015481146113cd5760405162461bcd60e51b8152600401610b8090617c70565b509392505050565b606080600080600060046000876001600160a01b03166001600160a01b031681526020019081526020016000206004019050600081600101546001600160401b03811115611425576114256176ea565b60405190808252806020026020018201604052801561144e578160200160208202803683370190505b509050600082600101546001600160401b0381111561146f5761146f6176ea565b604051908082528060200260200182016040528015611498578160200160208202803683370190505b50905060005b83600101548110156115505783546000906114b990836161ed565b60008181526002870160205260409020548551919250908590849081106114e2576114e2617d8e565b602090810291909101810191909152600082815260028701909152604090206001015483516001600160a01b039091169084908490811061152557611525617d8e565b6001600160a01b0390921660209283029190910190910152506115498160016161ed565b905061149e565b506003830154925491989097509195509350915050565b600061157282611a67565b6115b45760405162461bcd60e51b815260206004820152601360248201527204e6f742076616c696461746f722067726f757606c1b6044820152606401610b80565b506001600160a01b03166000908152600360208190526040909120015490565b60006018602160991b013b63ffffffff1615611660576115f26161f9565b6001600160a01b0316633b1eb4bf836040518263ffffffff1660e01b815260040161161f91815260200190565b602060405180830381865afa15801561163c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f399190617da4565b610f398261166c614760565b6167c8565b606060058054806020026020016040519081016040528092919081815260200182805480156116c957602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116116ab575b5050505050905090565b60006116dd61633b565b6060600060f46001600160a01b0316846040516020016116fd9190617d72565b60408051601f198184030181529082905261171791617d72565b600060405180830381855afa9150503d8060008114611752576040519150601f19603f3d011682016040523d82523d6000602084013e611757565b606091505b5092509050806117cf5760405162461bcd60e51b815260206004820152603860248201527f6572726f722063616c6c696e672067657456657269666965645365616c42697460448201527f6d617046726f6d48656164657220707265636f6d70696c6500000000000000006064820152608401610b80565b6117da826000616802565b949350505050565b604051674163636f756e747360c01b602082015260009060280160408051601f1981840301815290829052805160209091012060025463dcf0aaed60e01b8352600483018290529091339161010090046001600160a01b03169063dcf0aaed90602401602060405180830381865afa158015611862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118869190617c53565b6001600160a01b0316146118d75760405162461bcd60e51b81526020600482015260186024820152771bdb9b1e481c9959da5cdd195c99590818dbdb9d1c9858dd60421b6044820152606401610b80565b6118e0866157ba565b6118fc5760405162461bcd60e51b8152600401610b8090617cc7565b600060046000886001600160a01b03166001600160a01b03168152602001908152602001600020905061196781888888888080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061685f92505050565b6119b35760405162461bcd60e51b815260206004820152601f60248201527f4572726f72207570646174696e67204543445341207075626c6963206b6579006044820152606401610b80565b5060019695505050505050565b6000806119cb615ea0565b6040516393c5c48760e01b81526001600160a01b03858116600483015291909116906393c5c48790602401602060405180830381865afa158015611a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a379190617c53565b9050611a42816157ba565b611a5e5760405162461bcd60e51b8152600401610b8090617cc7565b610c7281610da4565b6001600160a01b031660009081526003602052604090205460ff1690565b6000611a8f61696b565b6009805484141580611aa5575080600101548314155b611af15760405162461bcd60e51b815260206004820152601e60248201527f47726f757020726571756972656d656e7473206e6f74206368616e67656400006044820152606401610b80565b60408051808201825285815260209081018590526009869055600a85905581518681529081018590527f999f7ee1917e6d7ea08360edfe9250cda3eda859c38dcb71a92623665de64dd491015b60405180910390a15060019392505050565b6000611b5a61633b565b604080516020810185905290810183905260609060009060fa90830160408051601f1981840301815290829052611b9091617d72565b600060405180830381855afa9150503d8060008114611bcb576040519150601f19603f3d011682016040523d82523d6000602084013e611bd0565b606091505b509250905080611c415760405162461bcd60e51b815260206004820152603660248201527f6572726f722063616c6c696e672076616c696461746f725369676e65724164646044820152757265737346726f6d53657420707265636f6d70696c6560501b6064820152608401610b80565b611c4c8260006169c5565b95945050505050565b60006001806000828254611c699190617c40565b9091555050600154611c7b8484614102565b91506001548114611c9e5760405162461bcd60e51b8152600401610b8090617c70565b5092915050565b60006001806000828254611cb99190617c40565b90915550506001546000611ccb615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015611d11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d359190617c53565b9050611d4081611a67565b611d5c5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0381166000908152600360208190526040909120015415611dc25760405162461bcd60e51b815260206004820152601960248201527856616c696461746f722067726f7570206e6f7420656d70747960381b6044820152606401610b80565b6001600160a01b0381166000908152600360205260409020600801805460011015611e745742611e1d60096001015483600181548110611e0457611e04617d8e565b90600052602060002001546161ed90919063ffffffff16565b10611e745760405162461bcd60e51b815260206004820152602160248201527f4861736e2774206265656e20656d70747920666f72206c6f6e6720656e6f75676044820152600d60fb1b6064820152608401610b80565b6001600160a01b03821660009081526003602081905260408220805460ff19168155600181018390556002810183905590810182905560058101829055600681018290556007810182905590611ecd6008830182617561565b50600060098201819055600a8201819055600b8201819055600c8201819055600d90910155611efe600583876169d1565b6040516001600160a01b038316907fae7e034b0748a10a219b46074b20977a9170bf4027b156c797093773619a866990600090a26001935050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b6000611f6361633b565b6060600060f66001600160a01b031684604051602001611f839190617d72565b60408051601f1981840301815290829052611f9d91617d72565b600060405180830381855afa9150503d8060008114611fd8576040519150601f19603f3d011682016040523d82523d6000602084013e611fdd565b606091505b5092509050806117cf5760405162461bcd60e51b815260206004820152602360248201527f6572726f722063616c6c696e67206861736848656164657220707265636f6d70604482015262696c6560e81b6064820152608401610b80565b600180600082825461204d9190617c40565b909155505060015461205d61696b565b601082905560015481146120835760405162461bcd60e51b8152600401610b8090617c70565b5050565b61208f61696b565b600f5481036120ec5760405162461bcd60e51b815260206004820152602360248201527f636f6d6d697373696f6e207570646174652064656c6179206e6f74206368616e60448201526219d95960ea1b6064820152608401610b80565b600f8190556040518181527ff2da07d08fd8dc9c5dcf87ad6f540e306f884a47dd8de14b718a4d5395f1ca9b9060200160405180910390a150565b60606000826001600160401b03811115612143576121436176ea565b60405190808252806020026020018201604052801561216c578160200160208202803683370190505b50905060005b838110156113cd576121a485858381811061218f5761218f617d8e565b90506020020160208101906106349190617614565b8282815181106121b6576121b6617d8e565b60209081029190910101526121cc8160016161ed565b9050612172565b6121db61696b565b6121e56000616b4b565b565b60006121f161633b565b6121fa43614a76565b905090565b600061220961696b565b600780548414158061221f575080600101548314155b6122765760405162461bcd60e51b815260206004820152602260248201527f56616c696461746f7220726571756972656d656e7473206e6f74206368616e67604482015261195960f21b6064820152608401610b80565b60408051808201825285815260209081018590526007869055600885905581518681529081018590527f62d947118dd4c1f5ece7f787a9cad4e1127d14d403b71133e95792b473bf83899101611b3e565b60006122d1615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015612317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233b9190617c53565b905061234681611a67565b6123625760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b038116600090815260036020908152604080832081518084018352939093528051918201905283815261239d610b3b615a31565b6124045760405162461bcd60e51b815260206004820152603260248201527f566f7465722072657761726420636f6d6d697373696f6e2063616e27742062656044820152712067726561746572207468616e203130302560701b6064820152608401610b80565b604080516020810190915260125490819052815111156124365760405162461bcd60e51b8152600401610b8090617dbd565b600082600d015460000361244d5782600b01612452565b82600c015b604080516020810190915290548082528351919250036124c65760405162461bcd60e51b815260206004820152602960248201527f566f7465722072657761726420636f6d6d697373696f6e206d75737420626520604482015268191a5999995c995b9d60ba1b6064820152608401610b80565b8151600c840155600f546000906124dd9043617c40565b600d850181905560408051888152602081018390529192506001600160a01b038716917f4db5e9c155a624051fb60d23ce6897f5144b5d3ef48bfd0ee5217606ed848940910160405180910390a2505050505050565b600061253d615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015612583573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a79190617c53565b90506125b281611a67565b6125ce5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b03811660009081526003602052604090206125f56125f1615a31565b5190565b8311156126145760405162461bcd60e51b8152600401610b8090617e08565b604080516020810190915260058201549081905283036126765760405162461bcd60e51b815260206004820152601c60248201527f436f6d6d697373696f6e206d75737420626520646966666572656e74000000006044820152606401610b80565b604080516020808201835260009091528151908101909152838152516006820155600f546126a59043906161ed565b600782018190556040516001600160a01b038416917f557d39a57520d9835859d4b7eda805a7f4115a59c3a374eeed488436fc62a152916126ee91878252602082015260400190565b60405180910390a2505050565b60006018602160991b013b63ffffffff161561277a576127196161f9565b6001600160a01b031663639a84d36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612756573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa9190617da4565b6121fa616b9b565b600061278c61633b565b6060600060f76001600160a01b0316846040516020016127ac9190617d72565b60408051601f19818403018152908290526127c691617d72565b600060405180830381855afa9150503d8060008114612801576040519150601f19603f3d011682016040523d82523d6000602084013e612806565b606091505b5092509050806128725760405162461bcd60e51b815260206004820152603160248201527f6572726f722063616c6c696e6720676574426c6f636b4e756d62657246726f6d60448201527048656164657220707265636f6d70696c6560781b6064820152608401610b80565b6117da8260006169c5565b600060018060008282546128919190617c40565b909155505060015460006128a3615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa1580156128e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290d9190617c53565b9050612918816157ba565b6129345760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b038082166000908152600460205260409020600281015490911615612a455760028101546001600160a01b0390811660009081526003602052604090819020905163542424fb60e01b81526001909101600482015290831660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af41580156129d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129f89190617e4d565b15612a455760405162461bcd60e51b815260206004820152601e60248201527f486173206265656e2067726f7570206d656d62657220726563656e746c7900006044820152606401610b80565b6008546007820154600091612a5a91906161ed565b9050428110612aab5760405162461bcd60e51b815260206004820152601c60248201527f4e6f742079657420726571756972656d656e7420656e642074696d65000000006044820152606401610b80565b612ab7600684886169d1565b6001600160a01b0383166000908152600460205260408120908181612adc828261757f565b612aea60018301600061757f565b5050506002810180546001600160a01b0319169055600060038201819055600482018190556005820181905560079091018190556040516001600160a01b038516917f51407fafe7ef9bec39c65a12a4885a274190991bf1e9057fcc384fc77ff1a7f091a2600194505050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b6001600160a01b038216600090815260036020526040808220905163b1cfea4360e01b81526001909101600482015260248101839052606091907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063b1cfea4390604401600060405180830381865af4158015612bed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612c159190810190617e6f565b90506000836001600160401b03811115612c3157612c316176ea565b604051908082528060200260200182016040528015612c5a578160200160208202803683370190505b5090506000612c67615ea0565b905060005b85811015612d4557816001600160a01b0316634ce38b5f858381518110612c9557612c95617d8e565b60200260200101516040518263ffffffff1660e01b8152600401612cc891906001600160a01b0391909116815260200190565b602060405180830381865afa158015612ce5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d099190617c53565b838281518110612d1b57612d1b617d8e565b6001600160a01b0390921660209283029190910190910152612d3e8160016161ed565b9050612c6c565b509095945050505050565b612d5861696b565b612d606161f9565b6001600160a01b0316634406d6616040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dc19190617e4d565b15612e3e5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f7420757064617465206d617820766f74657220726577617264206360448201527f6f6d6d697373696f6e20647572696e672065706f63682070726f63657373696e6064820152606760f81b608482015260a401610b80565b604080516020808201835260009091528151908101909152818152612e64610b3b615a31565b612ecf5760405162461bcd60e51b815260206004820152603660248201527f4d617820766f7465722072657761726420636f6d6d697373696f6e2063616e27604482015275742062652067726561746572207468616e203130302560501b6064820152608401610b80565b604080516020810190915260125490819052815103612f405760405162461bcd60e51b815260206004820152602760248201527f4d617820766f7465722072657761726420636f6d6d697373696f6e206e6f742060448201526618da185b99d95960ca1b6064820152608401610b80565b60408051602081019091526012549081905281511015612f5f57436013555b80516012556040518281527f99cfb385bfbddf7c5a35a50d42eab6eef264db0850955419eb205a1a89a72dab9060200160405180910390a15050565b60006001806000828254612faf9190617c40565b90915550506001546000612fc1615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613007573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061302b9190617c53565b905061303681611a67565b6130705760405162461bcd60e51b815260206004820152600b60248201526a04e6f7420612067726f75760ac1b6044820152606401610b80565b613079866157ba565b6130955760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b0381811660009081526003602052604090819020905163542424fb60e01b81526001820160048201529188166024830152907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af415801561310a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061312e9190617e4d565b6131765760405162461bcd60e51b815260206004820152601960248201527804e6f742061206d656d626572206f66207468652067726f757603c1b6044820152606401610b80565b60405163597c7f4b60e11b81526001820160048201526001600160a01b0380891660248301528088166044830152861660648201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063b2f8fe969060840160006040518083038186803b1580156131e257600080fd5b505af41580156131f6573d6000803e3d6000fd5b50506040516001600160a01b03808b169350851691507f38819cc49a343985b478d72f531a35b15384c398dd80fd191a14662170f895c690600090a360019350505060015481146113cd5760405162461bcd60e51b8152600401610b8090617c70565b60006121fa436115d4565b600061326e61633b565b6060600060f96001600160a01b03168460405160200161329091815260200190565b60408051601f19818403018152908290526132aa91617d72565b600060405180830381855afa9150503d80600081146132e5576040519150601f19603f3d011682016040523d82523d6000602084013e6132ea565b606091505b5092509050806128725760405162461bcd60e51b815260206004820152602e60248201527f6572726f722063616c6c696e67206e756d62657256616c696461746f7273496e60448201526d53657420707265636f6d70696c6560901b6064820152608401610b80565b60606000806000606060008061336888611a67565b6133845760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b038816600090815260036020526040908190209051637f1e3d4760e11b81526001820160048201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063fe3c7a8e90602401600060405180830381865af41580156133ef573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526134179190810190617e6f565b60408051602081019091526005830154908190526040805160208101909152600684015490819052600784015460408051602081019091526009860154908190526008860190600a8701548254604080516020808402820181019092528281529185918301828280156134a957602002820191906000526020600020905b815481526020019060010190808311613495575b50505050509250975097509750975097509750975050919395979092949650565b60025460ff161561351d5760405162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a6564000000006044820152606401610b80565b6002805460ff1916600117905561353333616b4b565b61353c89613584565b6135468888611a85565b5061355186866121ff565b5061355b8261484f565b506135668135612087565b61356f84615645565b506135798361203b565b505050505050505050565b61358c61696b565b6001600160a01b0381166135e25760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f7420726567697374657220746865206e756c6c20616464726573736044820152606401610b80565b60028054610100600160a81b0319166101006001600160a01b038416908102919091179091556040517f27fe5f0c1c3b1ed427cc63d0f05759ffdecf9aec9e18d31ef366fc8a6cb5dc3b90600090a250565b600061363e615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613684573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136a89190617c53565b90506136b381611a67565b6136cf5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b03811660009081526003602052604090206136ef6161f9565b6001600160a01b0316634406d6616040518163ffffffff1660e01b8152600401602060405180830381865afa15801561372c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137509190617e4d565b156137c35760405162461bcd60e51b815260206004820152603d60248201527f43616e6e6f742075706461746520766f7465722072657761726420636f6d6d6960448201527f7373696f6e20647572696e672065706f63682070726f63657373696e670000006064820152608401610b80565b80600d01546000036138285760405162461bcd60e51b815260206004820152602860248201527f4e6f20766f7465722072657761726420636f6d6d697373696f6e20757064617460448201526719481c5d595d595960c21b6064820152608401610b80565b4381600d015411156138935760405162461bcd60e51b815260206004820152602e60248201527f43616e2774206170706c7920766f7465722072657761726420636f6d6d69737360448201526d1a5bdb881d5c19185d19481e595d60921b6064820152608401610b80565b60135481600d01541161391a5760405162461bcd60e51b815260206004820152604360248201527f566f7465722072657761726420636f6d6d697373696f6e20636170207265647560448201527f6365642073696e6365207175657565643b2072652d71756575652072657175696064820152621c995960ea1b608482015260a401610b80565b604080516020808201835260125482528251908101909252600c8301549182905251101561395a5760405162461bcd60e51b8152600401610b8090617dbd565b600c81018054600b830181905560408051602080820183526000918290528251808201845282905293819055600d85015580519283019052908190526001600160a01b038316907f4fdad274bc1c02c1dbcb516958124a63015f21accccf151f1440d5d255c5a5c6905b60405190815260200160405180910390a25050565b600060018060008282546139ed9190617c40565b909155505060015460006139ff615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613a45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a699190617c53565b9050613a74816157ba565b613a905760405162461bcd60e51b8152600401610b8090617cc7565b613a9984611a67565b613ab55760405162461bcd60e51b8152600401610b8090617c98565b613abe81613f6b565b613b165760405162461bcd60e51b815260206004820152602360248201527f56616c696461746f7220646f65736e2774206d65657420726571756972656d656044820152626e747360e81b6064820152608401610b80565b613b1f84613f6b565b613b6b5760405162461bcd60e51b815260206004820152601f60248201527f47726f757020646f65736e2774206d65657420726571756972656d656e7473006044820152606401610b80565b6001600160a01b038082166000908152600460205260409020600281015490911615613b9d57613b9b8183616c83565b505b6002810180546001600160a01b0319166001600160a01b0387811691821790925560405190918416907f91ef92227057e201e406c3451698dd780fe7672ad74328591c88d281af31581d90600090a36001935050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b6001806000828254613c259190617c40565b90915550506001546000613c37615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015613c7d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ca19190617c53565b9050613cac81611a67565b613cc85760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0381166000908152600360205260409020601054600a820154613cf1916161ed565b421015613d665760405162461bcd60e51b815260206004820152603b60248201527f607265736574536c617368696e674d756c7469706c696572602063616c6c656460448201527f206265666f7265207265736574506572696f64206578706972656400000000006064820152608401610b80565b613d6e615a31565b51600990910155506001548114613d975760405162461bcd60e51b8152600401610b8090617c70565b50565b6000613da5826157ba565b613dc15760405162461bcd60e51b8152600401610b8090617cc7565b506001600160a01b039081166000908152600460205260409020600201541690565b6001806000828254613df59190617c40565b9091555050600154613e05616d94565b6040516357601c5d60e01b81523360048201526001600160a01b0391909116906357601c5d90602401602060405180830381865afa158015613e4b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e6f9190617e4d565b613ebb5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c6044820152606401610b80565b613ec482611a67565b613ee05760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0382166000908152600360209081526040918290208251918201909252600982015490819052613f3d90613f1f906002905b90616dcd565b60408051602080820183526000909152815190810190915290815290565b51600982015542600a9091015560015481146120835760405162461bcd60e51b8152600401610b8090617c70565b600080613f76616d94565b6040516330ec70f560e01b81526001600160a01b03858116600483015291909116906330ec70f590602401602060405180830381865afa158015613fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fe29190617da4565b9050613fed83614678565b613ff882600a6161ed565b10159392505050565b600060018060008282546140159190617c40565b90915550506001546000614027615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa15801561406d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140919190617c53565b6001600160a01b038116600090815260036020819052604090912001549091506140f55760405162461bcd60e51b815260206004820152601560248201527456616c696461746f722067726f757020656d70747960581b6044820152606401610b80565b610d7a81856000806163a9565b600060018060008282546141169190617c40565b90915550506001546000614128615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa15801561416e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141929190617c53565b905061419d81616dd9565b6141a6816157ba565b1580156141b957506141b781611a67565b155b6141fa5760405162461bcd60e51b8152602060048201526012602482015271105b1c9958591e481c9959da5cdd195c995960721b6044820152606401610b80565b6000614204616d94565b6040516330ec70f560e01b81526001600160a01b03848116600483015291909116906330ec70f590602401602060405180830381865afa15801561424c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142709190617da4565b6007549091508110156142b95760405162461bcd60e51b815260206004820152601160248201527011195c1bdcda5d081d1bdbc81cdb585b1b607a1b6044820152606401610b80565b6001600160a01b0382166000908152600460205260408120906142da615ea0565b604051634ce38b5f60e01b81526001600160a01b0386811660048301529190911690634ce38b5f90602401602060405180830381865afa158015614322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143469190617c53565b905061438a8285838b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061685f92505050565b6143d65760405162461bcd60e51b815260206004820152601f60248201527f4572726f72207570646174696e67204543445341207075626c6963206b6579006044820152606401610b80565b6006805460018101825560009182527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0180546001600160a01b0319166001600160a01b03871617905561442b908590616f74565b506040516001600160a01b038516907fd09501348473474a20c772c79c653e1fd7e8b437e418fe235d277d2c8885325190600090a260019550505050506001548114611c9e5760405162461bcd60e51b8152600401610b8090617c70565b60606000614495615ea0565b6006549091506000906001600160401b038111156144b5576144b56176ea565b6040519080825280602002602001820160405280156144de578160200160208202803683370190505b50905060005b8151811015611c9e57826001600160a01b0316634ce38b5f6006838154811061450f5761450f617d8e565b60009182526020909120015460405160e083901b6001600160e01b03191681526001600160a01b039091166004820152602401602060405180830381865afa15801561455f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145839190617c53565b82828151811061459557614595617d8e565b6001600160a01b03909216602092830291909101909101526145b88160016161ed565b90506144e4565b606060068054806020026020016040519081016040528092919081815260200182805480156116c9576020028201919060005260206000209081546001600160a01b031681526001909101906020018083116116ab575050505050905090565b600061462a82611a67565b6146465760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0382166000908152600360209081526040918290208251918201909252600982015490819052610c72565b6000614683826157ba565b1561469057505060075490565b61469982611a67565b15614758576001600160a01b0382166000908152600360208190526040822001546146c6906001906171e6565b6001600160a01b03841660009081526003602052604090206008018054919250901561474b5780546000906146fc9060016161e1565b90505b80156147495742614721600960010154848481548110611e0457611e04617d8e565b106147375761473081846171e6565b9250614749565b6147428160016161e1565b90506146ff565b505b6009546117da90836171fc565b506000919050565b600061476a61633b565b604051600160f81b602082015260609060009060f89060210160408051601f198184030181529082905261479d91617d72565b600060405180830381855afa9150503d80600081146147d8576040519150601f19603f3d011682016040523d82523d6000602084013e6147dd565b606091505b50925090508061483d5760405162461bcd60e51b815260206004820152602560248201527f6572726f722063616c6c696e672067657445706f636853697a6520707265636f6044820152646d70696c6560d81b6064820152608401610b80565b6148488260006169c5565b9250505090565b600061485961696b565b816000106148a95760405162461bcd60e51b815260206004820152601d60248201527f4d61782067726f75702073697a652063616e6e6f74206265207a65726f0000006044820152606401610b80565b600e5482036148fa5760405162461bcd60e51b815260206004820152601a60248201527f4d61782067726f75702073697a65206e6f74206368616e6765640000000000006044820152606401610b80565b600e8290556040518281527f603fe12c33c253a23da1680aa453dc70c3a0ee07763569bd5f602406ebd4e5d5906020015b60405180910390a1506001919050565b600180600082825461494d9190617c40565b909155505060015461495d616d94565b6040516357601c5d60e01b81523360048201526001600160a01b0391909116906357601c5d90602401602060405180830381865afa1580156149a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149c79190617e4d565b614a135760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79207265676973746572656420736c61736865722063616e2063616c6c6044820152606401610b80565b614a1c826157ba565b15614a55576001600160a01b038083166000908152600460205260409020600281015490911615614a5357614a518184616c83565b505b505b60015481146120835760405162461bcd60e51b8152600401610b8090617c70565b6000614a8061633b565b610f396003613f196002614a9e6002614a9888613264565b906171fc565b906161ed565b6001600160a01b038216600090815260036020526040808220905163b1cfea4360e01b81526001909101600482015260248101839052606091907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063b1cfea4390604401600060405180830381865af4158015614b1a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526117da9190810190617e6f565b6000614b4c615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015614b92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614bb69190617c53565b9050614bc181611a67565b614bdd5760405162461bcd60e51b8152600401610b8090617c98565b6001600160a01b0381166000908152600360205260409020614bfe81617208565b8060070154600003614c525760405162461bcd60e51b815260206004820152601b60248201527f4e6f20636f6d6d697373696f6e207570646174652071756575656400000000006044820152606401610b80565b4381600701541115614cb05760405162461bcd60e51b815260206004820152602160248201527f43616e2774206170706c7920636f6d6d697373696f6e207570646174652079656044820152601d60fa1b6064820152608401610b80565b60068101805460058301819055600091829055600783019190915560408051602081019091528190526001600160a01b038316907f815d292dbc1a08dfb3103aabb6611233dd2393903e57bdf4c5b3db91198a826c906139c4565b6001806000828254614d1d9190617c40565b90915550506001546040516b22b837b1b426b0b730b3b2b960a11b6020820152602c0160408051601f1981840301815290829052805160209091012060025463dcf0aaed60e01b8352600483018290529091339161010090046001600160a01b03169063dcf0aaed90602401602060405180830381865afa158015614da6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614dca9190617c53565b6001600160a01b031614614e1b5760405162461bcd60e51b81526020600482015260186024820152771bdb9b1e481c9959da5cdd195c99590818dbdb9d1c9858dd60421b6044820152606401610b80565b614e236172cc565b6040516340c10f1960e01b8152336004820152602481018590526001600160a01b0391909116906340c10f19906044016020604051808303816000875af1158015614e72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614e969190617e4d565b614a535760405162461bcd60e51b815260206004820152601c60248201527f6d696e74206661696c656420746f2065706f6368206d616e61676572000000006044820152606401610b80565b6000614eed846157ba565b614f095760405162461bcd60e51b8152600401610b8090617cc7565b614f11613259565b831115614f6c5760405162461bcd60e51b815260206004820152602360248201527f45706f63682063616e6e6f74206265206c6172676572207468616e2063757272604482015262195b9d60ea1b6064820152608401610b80565b6001600160a01b03841660009081526004602081905260409091206005810154910180549091614f9c91906161ed565b8310614fe05760405162461bcd60e51b8152602060048201526013602482015272696e646578206f7574206f6620626f756e647360681b6044820152606401610b80565b80548310801590614ff5575060008160010154115b6150375760405162461bcd60e51b8152602060048201526013602482015272696e646578206f7574206f6620626f756e647360681b6044820152606401610b80565b6000838152600282016020526040812054600180840154918714929161505c916161e1565b83546150699087906161e1565b6000878152600286016020526040812054919092149250871180156150b657508660028501600061509b8960016161ed565b81526020019081526020016000206000015411806150b65750815b905082806150c15750805b6151435760405162461bcd60e51b815260206004820152604760248201527f70726f766964656420696e64657820646f6573206e6f74206d6174636820707260448201527f6f76696465642065706f63684e756d62657220617420696e64657820696e206860648201526634b9ba37b93c9760c91b608482015260a401610b80565b50505060009283526002016020525060409020600101546001600160a01b031692915050565b60008061517461633b565b861580159061518257508415155b6151c65760405162461bcd60e51b8152602060048201526015602482015274612064656e6f6d696e61746f72206973207a65726f60581b6044820152606401610b80565b60408051602081018a905290810188905260608181018890526080820187905260a0820186905260c082018590526000918291829160fc9060e00160408051601f198184030181529082905261521b91617d72565b600060405180830381855afa9150503d8060008114615256576040519150601f19603f3d011682016040523d82523d6000602084013e61525b565b606091505b509092509050816152be5760405162461bcd60e51b815260206004820152602760248201527f6572726f722063616c6c696e67206672616374696f6e4d756c45787020707265604482015266636f6d70696c6560c81b6064820152608401610b80565b6152c98160006169c5565b93506152d68160206169c5565b939c939b50929950505050505050505050565b600060018060008282546152fd9190617c40565b90915550506001546153106125f1615a31565b83111561532f5760405162461bcd60e51b8152600401610b8090617e08565b6000615339615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa15801561537f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906153a39190617c53565b90506153ae81616dd9565b6153b7816157ba565b156154045760405162461bcd60e51b815260206004820152601f60248201527f416c726561647920726567697374657265642061732076616c696461746f72006044820152606401610b80565b61540d81611a67565b1561545a5760405162461bcd60e51b815260206004820152601b60248201527f416c726561647920726567697374657265642061732067726f757000000000006044820152606401610b80565b6000615464616d94565b6040516330ec70f560e01b81526001600160a01b03848116600483015291909116906330ec70f590602401602060405180830381865afa1580156154ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906154d09190617da4565b60095490915081101561551e5760405162461bcd60e51b8152602060048201526016602482015275139bdd08195b9bdd59da081b1bd8dad9590819dbdb1960521b6044820152606401610b80565b6001600160a01b0382166000908152600360205260409020805460ff191660011781556155638660408051602080820183526000909152815190810190915290815290565b516005820155604080518082019091528061557c615a31565b8152600060209182018190528251516009850155910151600a8301556005805460018101825591527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b0385166001600160a01b031990911681179091556040517fbf4b45570f1907a94775f8449817051a492a676918e38108bb762e991e6b58dc906156159089815260200190565b60405180910390a2600194505050506001548114610d9e5760405162461bcd60e51b8152600401610b8090617c70565b600061564f61696b565b816000106156b05760405162461bcd60e51b815260206004820152602860248201527f4d656d6265727368697020686973746f7279206c656e6774682063616e6e6f74604482015267206265207a65726f60c01b6064820152608401610b80565b600d54820361570f5760405162461bcd60e51b815260206004820152602560248201527f4d656d6265727368697020686973746f7279206c656e677468206e6f74206368604482015264185b99d95960da1b6064820152608401610b80565b600d8290556040518281527f1c75c7fb3ee9d13d8394372d8c7cdf1702fa947faa03f6ccfa500f787b09b48a9060200161492b565b61574c61696b565b6001600160a01b0381166157b15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610b80565b613d9781616b4b565b6001600160a01b038116600090815260046020526040812080548291906157e090617cf0565b9050119050919050565b60006157f461633b565b6060600060f56001600160a01b03168460405160200161581691815260200190565b60408051601f198184030181529082905261583091617d72565b600060405180830381855afa9150503d806000811461586b576040519150601f19603f3d011682016040523d82523d6000602084013e615870565b606091505b5092509050806117cf5760405162461bcd60e51b815260206004820152602c60248201527f6572726f722063616c6c696e6720676574506172656e745365616c4269746d6160448201526b7020707265636f6d70696c6560a01b6064820152608401610b80565b600060018060008282546158eb9190617c40565b909155505060015460006158fd615ea0565b6040516364439b4360e01b81523360048201526001600160a01b0391909116906364439b4390602401602060405180830381865afa158015615943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906159679190617c53565b9050615972816157ba565b61598e5760405162461bcd60e51b8152600401610b8090617cc7565b6001600160a01b03808216600090815260046020526040902060028101549091166159fb5760405162461bcd60e51b815260206004820152601b60248201527f6465616666696c696174653a206e6f7420616666696c696174656400000000006044820152606401610b80565b615a058183616c83565b506001935050506001548114615a2d5760405162461bcd60e51b8152600401610b8090617c70565b5090565b60408051602080820183526000909152815190810190915269d3c21bcecceda1000000815290565b6040805160208101909152600081527601357c299a88ea76a58924d52ce4f26a85af186c2b9e74821115615aee5760405162461bcd60e51b815260206004820152603660248201527f63616e277420637265617465206669786964697479206e756d626572206c6172604482015275676572207468616e206d61784e65774669786564282960501b6064820152608401610b80565b604051806020016040528069d3c21bcecceda100000084615b0f9190617f20565b905292915050565b60408051602081019091526000815282511580615b3357508151155b15615b4d5750604080516020810190915260008152610f39565b815169d3c21bcecceda0ffffff1901615b67575081610f39565b825169d3c21bcecceda0ffffff1901615b81575080610f39565b600069d3c21bcecceda1000000615b9785617306565b51615ba29190617f4d565b90506000615baf85617345565b519050600069d3c21bcecceda1000000615bc886617306565b51615bd39190617f4d565b90506000615be086617345565b5190506000615bef8386617f20565b90508415615c485782615c028683617f4d565b14615c485760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c5e4c4819195d1958dd195960521b6044820152606401610b80565b6000615c5e69d3c21bcecceda100000083617f20565b90508115615cc85769d3c21bcecceda1000000615c7b8383617f4d565b14615cc85760405162461bcd60e51b815260206004820152601f60248201527f6f766572666c6f772078317931202a20666978656431206465746563746564006044820152606401610b80565b9050806000615cd78587617f20565b90508515615d305784615cea8783617f4d565b14615d305760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c9e4c4819195d1958dd195960521b6044820152606401610b80565b6000615d3c8589617f20565b90508715615d955784615d4f8983617f4d565b14615d955760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c5e4c8819195d1958dd195960521b6044820152606401610b80565b615da464e8d4a5100088617f4d565b9650615db564e8d4a5100086617f4d565b94506000615dc38689617f20565b90508715615e1c5785615dd68983617f4d565b14615e1c5760405162461bcd60e51b81526020600482015260166024820152751bdd995c999b1bddc81e0c9e4c8819195d1958dd195960521b6044820152606401610b80565b6040805160208082018352878252825190810190925284825290615e41908290617390565b9050615e5b81604051806020016040528086815250617390565b9050615e7581604051806020016040528085815250617390565b9d9c50505050505050505050505050565b8051600090610f399069d3c21bcecceda100000090617f4d565b600254604051674163636f756e747360c01b602082015260009161010090046001600160a01b03169063dcf0aaed906028015b604051602081830303815290604052805190602001206040518263ffffffff1660e01b8152600401615f0791815260200190565b602060405180830381865afa158015615f24573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121fa9190617c53565b6001600160a01b0380831660008181526003602090815260408083208686168452600490925282206002015491939092911614615fc15760405162461bcd60e51b815260206004820152601760248201527604e6f7420616666696c696174656420746f2067726f757604c1b6044820152606401610b80565b60405163542424fb60e01b81526001820160048201526001600160a01b03841660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af4158015616022573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906160469190617e4d565b61608e5760405162461bcd60e51b815260206004820152601960248201527804e6f742061206d656d626572206f66207468652067726f757603c1b6044820152606401610b80565b60405163716062b560e11b81526001820160048201526001600160a01b03841660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063e2c0c56a9060440160006040518083038186803b1580156160ea57600080fd5b505af41580156160fe573d6000803e3d6000fd5b505050506003810154600081900361617657616118617410565b60405163a8e4587160e01b81526001600160a01b038781166004830152919091169063a8e4587190602401600060405180830381600087803b15801561615d57600080fd5b505af1158015616171573d6000803e3d6000fd5b505050505b616181846000616f74565b50616196856161918360016161ed565b617447565b836001600160a01b0316856001600160a01b03167fc7666a52a66ff601ff7c0d4d6efddc9ac20a34792f6aa003d1804c9d4d5baa5760405160405180910390a3506001949350505050565b6000610c728284617f61565b6000610c728284617c40565b6002546040516b22b837b1b426b0b730b3b2b960a11b602082015260009161010090046001600160a01b03169063dcf0aaed90602c01615ed3565b600061623e61633b565b6060600060fa6001600160a01b03168443604051602001616269929190918252602082015260400190565b60408051601f198184030181529082905261628391617d72565b600060405180830381855afa9150503d80600081146162be576040519150601f19603f3d011682016040523d82523d6000602084013e6162c3565b606091505b5092509050806128725760405162461bcd60e51b815260206004820152603d60248201527f6572726f722063616c6c696e672076616c696461746f725369676e657241646460448201527f7265737346726f6d43757272656e7453657420707265636f6d70696c650000006064820152608401610b80565b6018602160991b013b63ffffffff16156121e55760405162461bcd60e51b815260206004820152602960248201527f54686973206d6574686f64206973206e6f206c6f6e67657220737570706f727460448201526832b21034b71026191760b91b6064820152608401610b80565b60006163b485611a67565b80156163c457506163c4846157ba565b6164105760405162461bcd60e51b815260206004820152601760248201527f4e6f742076616c696461746f7220616e642067726f75700000000000000000006044820152606401610b80565b6001600160a01b0385166000908152600360208190526040909120600e54918101549091116164815760405162461bcd60e51b815260206004820152601f60248201527f67726f757020776f756c6420657863656564206d6178696d756d2073697a65006044820152606401610b80565b6001600160a01b038581166000908152600460205260409020600201548116908716146164ea5760405162461bcd60e51b815260206004820152601760248201527604e6f7420616666696c696174656420746f2067726f757604c1b6044820152606401610b80565b60405163542424fb60e01b81526001820160048201526001600160a01b03861660248201527308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af415801561654b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061656f9190617e4d565b156165af5760405162461bcd60e51b815260206004820152601060248201526f0416c726561647920696e2067726f75760841b6044820152606401610b80565b60038101546000906165c29060016161ed565b6040516326afac4960e01b81526001840160048201526001600160a01b03881660248201529091507308a4b5bc1b5adef0a283c8f0185ded6169f0bd29906326afac499060440160006040518083038186803b15801561662157600080fd5b505af4158015616635573d6000803e3d6000fd5b5050505061664287613f6b565b61668e5760405162461bcd60e51b815260206004820152601a60248201527f47726f757020726571756972656d656e7473206e6f74206d65740000000000006044820152606401610b80565b61669786613f6b565b6166e35760405162461bcd60e51b815260206004820152601e60248201527f56616c696461746f7220726571756972656d656e7473206e6f74206d657400006044820152606401610b80565b80600103616761576166f3617410565b60405163a18fb2db60e01b81526001600160a01b03898116600483015287811660248301528681166044830152919091169063a18fb2db90606401600060405180830381600087803b15801561674857600080fd5b505af115801561675c573d6000803e3d6000fd5b505050505b61676b8688616f74565b5061677b876161918360016161e1565b856001600160a01b0316876001600160a01b03167fbdf7e616a6943f81e07a7984c9d4c00197dc2f481486ce4ffa6af52a113974ad60405160405180910390a35060019695505050505050565b6000806167d58385617f4d565b90506167e18385617f74565b6000036167ef579050610f39565b6167fa8160016161ed565b915050610f39565b600061680f8260206161ed565b835110156168565760405162461bcd60e51b8152602060048201526014602482015273736c6963696e67206f7574206f662072616e676560601b6044820152606401610b80565b50016020015190565b600081516040146168b25760405162461bcd60e51b815260206004820152601d60248201527f57726f6e67204543445341207075626c6963206b6579206c656e6774680000006044820152606401610b80565b815160208301206001600160a01b038481169116146169135760405162461bcd60e51b815260206004820152601f60248201527f4543445341206b657920646f6573206e6f74206d61746368207369676e6572006044820152606401610b80565b8461691e8382617fd6565b50836001600160a01b03167f213377eec2c15b21fa7abcbb0cb87a67e893cdb94a2564aa4bb4d380869473c8836040516169589190618095565b60405180910390a2506001949350505050565b6000546001600160a01b031633146121e55760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b80565b6000610c728383616802565b825481108015616a0f5750816001600160a01b03168382815481106169f8576169f8617d8e565b6000918252602090912001546001600160a01b0316145b616a655760405162461bcd60e51b815260206004820152602160248201527f64656c657465456c656d656e743a20696e646578206f7574206f662072616e676044820152606560f81b6064820152608401610b80565b8254600090616a759060016161e1565b9050838181548110616a8957616a89617d8e565b9060005260206000200160009054906101000a90046001600160a01b0316848381548110616ab957616ab9617d8e565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550838181548110616af957616af9617d8e565b600091825260209091200180546001600160a01b03191690558354849080616b2357616b236180a8565b600082815260209020810160001990810180546001600160a01b031916905501905550505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000616ba561633b565b6040805143602082015260609160009160f9910160408051601f1981840301815290829052616bd391617d72565b600060405180830381855afa9150503d8060008114616c0e576040519150601f19603f3d011682016040523d82523d6000602084013e616c13565b606091505b50925090508061483d5760405162461bcd60e51b815260206004820152603560248201527f6572726f722063616c6c696e67206e756d62657256616c696461746f7273496e60448201527443757272656e7453657420707265636f6d70696c6560581b6064820152608401610b80565b6000616c8e826174f9565b60028301546001600160a01b0390811660008181526003602052604090819020905163542424fb60e01b8152600182016004820152928516602484015290917308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063542424fb90604401602060405180830381865af4158015616d09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616d2d9190617e4d565b15616d3e57616d3c8285615f48565b505b6002850180546001600160a01b03191690556040516001600160a01b0383811691908616907f71815121f0622b31a3e7270eb28acb9fd10825ff418c9a18591f617bb8a31a6c90600090a3506001949350505050565b60025460405169131bd8dad95911dbdb1960b21b602082015260009161010090046001600160a01b03169063dcf0aaed90602a01615ed3565b6000610c728284617f4d565b616de1617410565b60405163cb08c99360e01b81526001600160a01b038381166004830152919091169063cb08c993906024016020604051808303816000875af1158015616e2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616e4f9190617e4d565b15616eb35760405162461bcd60e51b815260206004820152602e60248201527f43616e6e6f7420766f746520666f72206d6f7265207468616e206d6178206e7560448201526d6d626572206f662067726f75707360901b6064820152608401610b80565b616ebb616d94565b6040516315952ae760e01b81526001600160a01b03838116600483015291909116906315952ae790602401602060405180830381865afa158015616f03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190616f279190617da4565b15613d975760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f742064656c656761746520676f7665726e616e636520706f7765726044820152606401610b80565b6001600160a01b038216600090815260046020819052604082200181616f98613259565b905060008260010154600014616fd057616fcb616fc3600185600101546161e190919063ffffffff16565b8454906161ed565b616fd3565b60005b905060008360010154118015616ff057506001600160a01b038516155b15616ffc574260038401555b6000836001015411801561701f5750600081815260028401602052604090205482145b15617079576040805180820182529283526001600160a01b03868116602080860191825260009485526002969096019095529120915182559151600191820180546001600160a01b03191691909316179091559050610f39565b60008360010154600014617097576170928260016161ed565b61709a565b60005b6040805180820182528581526001600160a01b038981166020808401918252600086815260028b0190915293909320915182559151600191820180546001600160a01b0319169190931617909155600d5490860154919250111561711157600184810154617107916161ed565b60018501556119b3565b600d5484600101540361715857835460009081526002850160205260408120908155600190810180546001600160a01b03191690558454617151916161ed565b84556119b3565b8354600090815260028501602081905260408220828155600190810180546001600160a01b03191690558654919291617190916161ed565b815260208101919091526040016000908120908155600190810180546001600160a01b0319169055848101546171c5916161e1565b600185015583546171d79060026161ed565b84555060019695505050505050565b60008183116171f55781610c72565b5090919050565b6000610c728284617f20565b604051637f1e3d4760e11b81526001820160048201526000907308a4b5bc1b5adef0a283c8f0185ded6169f0bd299063fe3c7a8e90602401600060405180830381865af415801561725d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526172859190810190617e6f565b905060005b81518110156172c7576172b58282815181106172a8576172a8617d8e565b60200260200101516174f9565b806172bf816180be565b91505061728a565b505050565b6002546040516a29ba30b13632aa37b5b2b760a91b602082015260009161010090046001600160a01b03169063dcf0aaed90602b01615ed3565b604080516020810190915260008152604051806020016040528069d3c21bcecceda100000080856000015161733b9190617f4d565b615b0f9190617f20565b604080516020810190915260008152604051806020016040528069d3c21bcecceda100000080856000015161737a9190617f4d565b6173849190617f20565b8451615b0f9190617f61565b604080516020810190915260008152815183516000916173af91617c40565b84519091508110156173fb5760405162461bcd60e51b8152602060048201526015602482015274185919081bdd995c999b1bddc819195d1958dd1959605a1b6044820152606401610b80565b60408051602081019091529081529392505050565b6002546040516722b632b1ba34b7b760c11b602082015260009161010090046001600160a01b03169063dcf0aaed90602801615ed3565b6001600160a01b03821660009081526003602052604090206008018054820361748457805460018101825560008281526020902042910155505050565b80548210156174b157428183815481106174a0576174a0617d8e565b600091825260209091200155505050565b60405162461bcd60e51b815260206004820152601d60248201527f556e61626c6520746f207570646174652073697a6520686973746f72790000006044820152606401610b80565b6175016161f9565b604051635915e07760e01b81526001600160a01b0383811660048301529190911690635915e07790602401600060405180830381600087803b15801561754657600080fd5b505af115801561755a573d6000803e3d6000fd5b5050505050565b5080546000825590600052602060002090810190613d9791906175b5565b50805461758b90617cf0565b6000825580601f1061759b575050565b601f016020900490600052602060002090810190613d9791905b5b80821115615a2d57600081556001016175b6565b6001600160a01b0381168114613d9757600080fd5b6000806000606084860312156175f457600080fd5b83356175ff816175ca565b95602085013595506040909401359392505050565b60006020828403121561762657600080fd5b8135610c72816175ca565b60006020828403121561764357600080fd5b5035919050565b60005b8381101561766557818101518382015260200161764d565b50506000910152565b6000815180845261768681602086016020860161764a565b601f01601f19169290920160200192915050565b60a0815260006176ad60a083018861766e565b82810360208401526176bf818861766e565b6001600160a01b03968716604085015260608401959095525050921660809092019190915292915050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715617728576177286176ea565b604052919050565b600082601f83011261774157600080fd5b81356001600160401b0381111561775a5761775a6176ea565b61776d601f8201601f1916602001617700565b81815284602083860101111561778257600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000606084860312156177b457600080fd5b83356177bf816175ca565b925060208401356001600160401b03808211156177db57600080fd5b6177e787838801617730565b935060408601359150808211156177fd57600080fd5b5061780a86828701617730565b9150509250925092565b60008060006060848603121561782957600080fd5b8335617834816175ca565b92506020840135617844816175ca565b91506040840135617854816175ca565b809150509250925092565b600081518084526020808501945080840160005b8381101561788f57815187529582019590820190600101617873565b509495945050505050565b600081518084526020808501945080840160005b8381101561788f5781516001600160a01b0316875295820195908201906001016178ae565b6080815260006178e6608083018761785f565b82810360208401526178f8818761789a565b604084019590955250506060015292915050565b602081526000610c72602083018461789a565b60006020828403121561793157600080fd5b81356001600160401b0381111561794757600080fd5b6117da84828501617730565b60008083601f84011261796557600080fd5b5081356001600160401b0381111561797c57600080fd5b60208301915083602082850101111561799457600080fd5b9250929050565b600080600080606085870312156179b157600080fd5b84356179bc816175ca565b935060208501356179cc816175ca565b925060408501356001600160401b038111156179e757600080fd5b6179f387828801617953565b95989497509550505050565b60008060408385031215617a1257600080fd5b50508035926020909101359150565b60008060208385031215617a3457600080fd5b82356001600160401b03811115617a4a57600080fd5b617a5685828601617953565b90969095509350505050565b60008060208385031215617a7557600080fd5b82356001600160401b0380821115617a8c57600080fd5b818501915085601f830112617aa057600080fd5b813581811115617aaf57600080fd5b8660208260051b8501011115617ac457600080fd5b60209290920196919550909350505050565b602081526000610c72602083018461785f565b60008060408385031215617afc57600080fd5b8235617b07816175ca565b946020939093013593505050565b60e081526000617b2860e083018a61789a565b8860208401528760408401528660608401528281036080840152617b4c818761785f565b60a0840195909552505060c0015295945050505050565b6000806000806000806000806000898b03610120811215617b8357600080fd5b8a35617b8e816175ca565b995060208b810135995060408c0135985060608c0135975060808c0135965060a08c0135955060c08c0135945060e08c0135935060ff1982011215617bd257600080fd5b506101008a0190509295985092959850929598565b60008060008060008060c08789031215617c0057600080fd5b505084359660208601359650604086013595606081013595506080810135945060a0013592509050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610f3957610f39617c2a565b600060208284031215617c6557600080fd5b8151610c72816175ca565b6020808252600e908201526d1c99595b9d1c985b9d0818d85b1b60921b604082015260600190565b60208082526015908201527404e6f7420612076616c696461746f722067726f757605c1b604082015260600190565b6020808252600f908201526e2737ba1030903b30b634b230ba37b960891b604082015260600190565b600181811c90821680617d0457607f821691505b602082108103610d9e57634e487b7160e01b600052602260045260246000fd5b6bffffffffffffffffffffffff198460601b16815260008351617d4e81601485016020880161764a565b835190830190617d6581601484016020880161764a565b0160140195945050505050565b60008251617d8481846020870161764a565b9190910192915050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215617db657600080fd5b5051919050565b6020808252602b908201527f566f7465722072657761726420636f6d6d697373696f6e20657863656564732060408201526a1b585e08185b1b1bddd95960aa1b606082015260800190565b60208082526025908201527f436f6d6d697373696f6e2063616e27742062652067726561746572207468616e604082015264203130302560d81b606082015260800190565b600060208284031215617e5f57600080fd5b81518015158114610c7257600080fd5b60006020808385031215617e8257600080fd5b82516001600160401b0380821115617e9957600080fd5b818501915085601f830112617ead57600080fd5b815181811115617ebf57617ebf6176ea565b8060051b9150617ed0848301617700565b8181529183018401918481019088841115617eea57600080fd5b938501935b83851015617f145784519250617f04836175ca565b8282529385019390850190617eef565b98975050505050505050565b8082028115828204841417610f3957610f39617c2a565b634e487b7160e01b600052601260045260246000fd5b600082617f5c57617f5c617f37565b500490565b81810381811115610f3957610f39617c2a565b600082617f8357617f83617f37565b500690565b601f8211156172c757600081815260208120601f850160051c81016020861015617faf5750805b601f850160051c820191505b81811015617fce57828155600101617fbb565b505050505050565b81516001600160401b03811115617fef57617fef6176ea565b61800381617ffd8454617cf0565b84617f88565b602080601f83116001811461803857600084156180205750858301515b600019600386901b1c1916600185901b178555617fce565b600085815260208120601f198616915b8281101561806757888601518255948401946001909101908401618048565b50858210156180855787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b602081526000610c72602083018461766e565b634e487b7160e01b600052603160045260246000fd5b6000600182016180d0576180d0617c2a565b506001019056fea2646970667358221220184590790187f92f0db5ee302e283f93ff6ff08d611d8c8a9df1b8e932d1db4664736f6c634300081300330000000000000000000000000000000000000000000000000000000000000000","name":"Validators","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"contracts/common/interfaces/IRegistry.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IRegistry {\n  function setAddressFor(string calldata, address) external;\n  function getAddressForOrDie(bytes32) external view returns (address);\n  function getAddressFor(bytes32) external view returns (address);\n  function getAddressForStringOrDie(string calldata identifier) external view returns (address);\n  function getAddressForString(string calldata identifier) external view returns (address);\n  function isOneOf(bytes32[] calldata, address) external view returns (bool);\n}\n"},{"file_path":"contracts/governance/interfaces/IGovernance.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IGovernance {\n  // constitution\n  function setConstitution(address destination, bytes4 functionId, uint256 threshold) external;\n  function getConstitution(address destination, bytes4 functionId) external view returns (uint256);\n\n  // proposal\n  function propose(\n    uint256[] calldata values,\n    address[] calldata destinations,\n    bytes calldata data,\n    uint256[] calldata dataLengths,\n    string calldata descriptionUrl\n  ) external payable returns (uint256);\n  function getProposal(\n    uint256 proposalId\n  ) external view returns (address, uint256, uint256, uint256, string memory, uint256, bool);\n  function proposalCount() external view returns (uint256);\n\n  // upvote\n  function upvote(uint256 proposalId, uint256 lesser, uint256 greater) external returns (bool);\n  function getUpvotes(uint256 proposalId) external view returns (uint256);\n\n  // approve\n  function approve(uint256 proposalId, uint256 index) external returns (bool);\n  function isApproved(uint256 proposalId) external view returns (bool);\n\n  // voting\n  // TODO: Enable once we migrate out of 0.5\n  // function vote(\n  //   uint256 proposalId,\n  //   uint256 index,\n  //   Proposals.VoteValue value\n  // ) external returns (bool);\n  function votePartially(\n    uint256 proposalId,\n    uint256 index,\n    uint256 yesVotes,\n    uint256 noVotes,\n    uint256 abstainVotes\n  ) external returns (bool);\n  function removeVotesWhenRevokingDelegatedVotes(\n    address account,\n    uint256 maxAmountAllowed\n  ) external;\n  function isVoting(address account) external view returns (bool);\n  function getVoteTotals(uint256 proposalId) external view returns (uint256, uint256, uint256);\n  function getAmountOfGoldUsedForVoting(address account) external view returns (uint256);\n\n  // referendum\n  function getReferendumStageDuration() external view returns (uint256);\n\n  // execution\n  function execute(uint256 proposalId, uint256 index) external returns (bool);\n}\n"},{"file_path":"contracts-0.8/common/PrecompilesOverride.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.7 <0.8.20;\n\nimport \"../../contracts/common/interfaces/ICeloVersionedContract.sol\";\nimport \"../../contracts-0.8/common/IsL2Check.sol\";\n\nimport \"./UsingPrecompiles.sol\";\nimport \"./UsingRegistry.sol\";\n\n/**\n * @title PrecompilesOverride Contract\n * @notice This contract allows for a smoother transition from L1 to L2\n * by abstracting away the usingPrecompile contract, and taking care of the L1 to L2 swtiching logic.\n **/\ncontract PrecompilesOverride is UsingPrecompiles, UsingRegistry {\n  /**\n   * @notice Returns the epoch number at a block.\n   * @param blockNumber Block number where epoch number is calculated.\n   * @return Epoch number.\n   */\n  function getEpochNumberOfBlock(uint256 blockNumber) public view override returns (uint256) {\n    if (isL2()) {\n      return getEpochManager().getEpochNumberOfBlock(blockNumber);\n    } else {\n      return epochNumberOfBlock(blockNumber, getEpochSize());\n    }\n  }\n\n  /**\n   * @notice Returns the epoch number at a block.\n   * @return Current epoch number.\n   */\n  function getEpochNumber() public view override returns (uint256) {\n    return getEpochNumberOfBlock(block.number);\n  }\n\n  /**\n   * @notice Gets a validator signer address from the current validator set.\n   * @param index Index of requested validator in the validator set.\n   * @return Address of validator signer at the requested index.\n   */\n  function validatorSignerAddressFromCurrentSet(\n    uint256 index\n  ) public view override returns (address) {\n    if (isL2()) {\n      return getEpochManager().getElectedSignerByIndex(index);\n    } else {\n      return super.validatorSignerAddressFromCurrentSet(index);\n    }\n  }\n\n  /**\n   * @notice Gets a validator address from the current validator set.\n   * @param index Index of requested validator in the validator set.\n   * @return Address of validator at the requested index.\n   */\n  function validatorAddressFromCurrentSet(uint256 index) public view onlyL2 returns (address) {\n    return getEpochManager().getElectedAccountByIndex(index);\n  }\n\n  /**\n   * @notice Gets the size of the current elected validator set.\n   * @return Size of the current elected validator set.\n   */\n  function numberValidatorsInCurrentSet() public view override returns (uint256) {\n    if (isL2()) {\n      return getEpochManager().numberOfElectedInCurrentSet();\n    } else {\n      return super.numberValidatorsInCurrentSet();\n    }\n  }\n}\n"},{"file_path":"contracts-0.8/common/UsingPrecompiles.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.0 <0.8.20;\n\n// Note: This is not an exact copy of UsingPrecompiles in the contract's folder, but in solidity 0.8\nimport \"@openzeppelin/contracts8/utils/math/SafeMath.sol\";\nimport \"../../contracts/common/interfaces/ICeloVersionedContract.sol\";\nimport \"../common/IsL2Check.sol\";\n\ncontract UsingPrecompiles is IsL2Check {\n  using SafeMath for uint256;\n\n  address constant TRANSFER = address(0xff - 2);\n  address constant FRACTION_MUL = address(0xff - 3);\n  address constant PROOF_OF_POSSESSION = address(0xff - 4);\n  address constant GET_VALIDATOR = address(0xff - 5);\n  address constant NUMBER_VALIDATORS = address(0xff - 6);\n  address constant EPOCH_SIZE = address(0xff - 7);\n  address constant BLOCK_NUMBER_FROM_HEADER = address(0xff - 8);\n  address constant HASH_HEADER = address(0xff - 9);\n  address constant GET_PARENT_SEAL_BITMAP = address(0xff - 10);\n  address constant GET_VERIFIED_SEAL_BITMAP = address(0xff - 11);\n  uint256 constant DAY = 86400;\n\n  /**\n   * @notice calculate a * b^x for fractions a, b to `decimals` precision\n   * @param aNumerator Numerator of first fraction\n   * @param aDenominator Denominator of first fraction\n   * @param bNumerator Numerator of exponentiated fraction\n   * @param bDenominator Denominator of exponentiated fraction\n   * @param exponent exponent to raise b to\n   * @param _decimals precision\n   * @return Numerator of the computed quantity (not reduced).\n   * @return Denominator of the computed quantity (not reduced).\n   * @dev This function will be deprecated in L2.\n   */\n  function fractionMulExp(\n    uint256 aNumerator,\n    uint256 aDenominator,\n    uint256 bNumerator,\n    uint256 bDenominator,\n    uint256 exponent,\n    uint256 _decimals\n  ) public view onlyL1 returns (uint256, uint256) {\n    require(aDenominator != 0 && bDenominator != 0, \"a denominator is zero\");\n    uint256 returnNumerator;\n    uint256 returnDenominator;\n    bool success;\n    bytes memory out;\n    (success, out) = FRACTION_MUL.staticcall(\n      abi.encodePacked(aNumerator, aDenominator, bNumerator, bDenominator, exponent, _decimals)\n    );\n    require(success, \"error calling fractionMulExp precompile\");\n    returnNumerator = getUint256FromBytes(out, 0);\n    returnDenominator = getUint256FromBytes(out, 32);\n    return (returnNumerator, returnDenominator);\n  }\n\n  /**\n   * @notice Returns the current epoch size in blocks.\n   * @return The current epoch size in blocks.\n   * @dev This function will be deprecated in L2.\n   */\n  function getEpochSize() public view onlyL1 returns (uint256) {\n    bytes memory out;\n    bool success;\n    (success, out) = EPOCH_SIZE.staticcall(abi.encodePacked(true));\n    require(success, \"error calling getEpochSize precompile\");\n    return getUint256FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Returns the epoch number at a block.\n   * @param blockNumber Block number where epoch number is calculated.\n   * @return Epoch number.\n   * @dev This function will be deprecated in L2.\n   */\n  function getEpochNumberOfBlock(uint256 blockNumber) public view virtual onlyL1 returns (uint256) {\n    return epochNumberOfBlock(blockNumber, getEpochSize());\n  }\n\n  /**\n   * @notice Returns the epoch number at a block.\n   * @return Current epoch number.\n   * @dev This function will be deprecated in L2.\n   */\n  function getEpochNumber() public view virtual onlyL1 returns (uint256) {\n    return getEpochNumberOfBlock(block.number);\n  }\n\n  /**\n   * @notice Gets a validator signer address from the current validator set.\n   * @param index Index of requested validator in the validator set.\n   * @return Address of validator signer at the requested index.\n   * @dev This function will be deprecated in L2.\n   */\n  function validatorSignerAddressFromCurrentSet(\n    uint256 index\n  ) public view virtual onlyL1 returns (address) {\n    bytes memory out;\n    bool success;\n    (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, uint256(block.number)));\n    require(success, \"error calling validatorSignerAddressFromCurrentSet precompile\");\n    return address(uint160(getUint256FromBytes(out, 0)));\n  }\n\n  /**\n   * @notice Gets a validator signer address from the validator set at the given block number.\n   * @param index Index of requested validator in the validator set.\n   * @param blockNumber Block number to retrieve the validator set from.\n   * @return Address of validator signer at the requested index.\n   * @dev This function will be deprecated in L2.\n   */\n  function validatorSignerAddressFromSet(\n    uint256 index,\n    uint256 blockNumber\n  ) public view virtual onlyL1 returns (address) {\n    bytes memory out;\n    bool success;\n    (success, out) = GET_VALIDATOR.staticcall(abi.encodePacked(index, blockNumber));\n    require(success, \"error calling validatorSignerAddressFromSet precompile\");\n    return address(uint160(getUint256FromBytes(out, 0)));\n  }\n\n  /**\n   * @notice Gets the size of the current elected validator set.\n   * @return Size of the current elected validator set.\n   * @dev This function will be deprecated in L2.\n   */\n  function numberValidatorsInCurrentSet() public view virtual onlyL1 returns (uint256) {\n    bytes memory out;\n    bool success;\n    (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(uint256(block.number)));\n    require(success, \"error calling numberValidatorsInCurrentSet precompile\");\n    return getUint256FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Gets the size of the validator set that must sign the given block number.\n   * @param blockNumber Block number to retrieve the validator set from.\n   * @return Size of the validator set.\n   * @dev This function will be deprecated in L2.\n   */\n  function numberValidatorsInSet(uint256 blockNumber) public view virtual onlyL1 returns (uint256) {\n    bytes memory out;\n    bool success;\n    (success, out) = NUMBER_VALIDATORS.staticcall(abi.encodePacked(blockNumber));\n    require(success, \"error calling numberValidatorsInSet precompile\");\n    return getUint256FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Checks a BLS proof of possession.\n   * @param sender The address signed by the BLS key to generate the proof of possession.\n   * @param blsKey The BLS public key that the validator is using for consensus, should pass proof\n   *   of possession. 48 bytes.\n   * @param blsPop The BLS public key proof-of-possession, which consists of a signature on the\n   *   account address. 96 bytes.\n   * @return True upon success.\n   * @dev This function will be deprecated in L2.\n   */\n  function checkProofOfPossession(\n    address sender,\n    bytes memory blsKey,\n    bytes memory blsPop\n  ) public view onlyL1 returns (bool) {\n    bool success;\n    (success, ) = PROOF_OF_POSSESSION.staticcall(abi.encodePacked(sender, blsKey, blsPop));\n    return success;\n  }\n\n  /**\n   * @notice Parses block number out of header.\n   * @param header RLP encoded header\n   * @return Block number.\n   * @dev This function will be deprecated in L2.\n   */\n  function getBlockNumberFromHeader(bytes memory header) public view onlyL1 returns (uint256) {\n    bytes memory out;\n    bool success;\n    (success, out) = BLOCK_NUMBER_FROM_HEADER.staticcall(abi.encodePacked(header));\n    require(success, \"error calling getBlockNumberFromHeader precompile\");\n    return getUint256FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Computes hash of header.\n   * @param header RLP encoded header\n   * @return Header hash.\n   * @dev This function will be deprecated in L2.\n   */\n  function hashHeader(bytes memory header) public view onlyL1 returns (bytes32) {\n    bytes memory out;\n    bool success;\n    (success, out) = HASH_HEADER.staticcall(abi.encodePacked(header));\n    require(success, \"error calling hashHeader precompile\");\n    return getBytes32FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Gets the parent seal bitmap from the header at the given block number.\n   * @param blockNumber Block number to retrieve. Must be within 4 epochs of the current number.\n   * @return Bitmap parent seal with set bits at indices corresponding to signing validators.\n   * @dev This function will be deprecated in L2.\n   */\n  function getParentSealBitmap(uint256 blockNumber) public view onlyL1 returns (bytes32) {\n    bytes memory out;\n    bool success;\n    (success, out) = GET_PARENT_SEAL_BITMAP.staticcall(abi.encodePacked(blockNumber));\n    require(success, \"error calling getParentSealBitmap precompile\");\n    return getBytes32FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Verifies the BLS signature on the header and returns the seal bitmap.\n   * The validator set used for verification is retrieved based on the parent hash field of the\n   * header.  If the parent hash is not in the blockchain, verification fails.\n   * @param header RLP encoded header\n   * @return Bitmap parent seal with set bits at indices correspoinding to signing validators.\n   * @dev This function will be deprecated in L2.\n   */\n  function getVerifiedSealBitmapFromHeader(\n    bytes memory header\n  ) public view onlyL1 returns (bytes32) {\n    bytes memory out;\n    bool success;\n    (success, out) = GET_VERIFIED_SEAL_BITMAP.staticcall(abi.encodePacked(header));\n    require(success, \"error calling getVerifiedSealBitmapFromHeader precompile\");\n    return getBytes32FromBytes(out, 0);\n  }\n\n  /**\n   * @notice Returns the minimum number of required signers for a given block number.\n   * @dev Computed in celo-blockchain as int(math.Ceil(float64(2*valSet.Size()) / 3))\n   * @dev This function will be deprecated in L2.\n   */\n  function minQuorumSize(uint256 blockNumber) public view onlyL1 returns (uint256) {\n    return numberValidatorsInSet(blockNumber).mul(2).add(2).div(3);\n  }\n\n  /**\n   * @notice Computes byzantine quorum from current validator set size\n   * @return Byzantine quorum of validators.\n   * @dev This function will be deprecated in L2.\n   */\n  function minQuorumSizeInCurrentSet() public view onlyL1 returns (uint256) {\n    return minQuorumSize(block.number);\n  }\n\n  /**\n   * @notice Returns the epoch number at a block.\n   * @param blockNumber Block number where epoch number is calculated.\n   * @param epochSize The epoch size in blocks.\n   * @return Epoch number.\n   */\n  function epochNumberOfBlock(\n    uint256 blockNumber,\n    uint256 epochSize\n  ) internal pure returns (uint256) {\n    // Follows GetEpochNumber from celo-blockchain/blob/master/consensus/istanbul/utils.go\n    uint256 epochNumber = blockNumber / epochSize;\n    if (blockNumber % epochSize == 0) {\n      return epochNumber;\n    } else {\n      return epochNumber.add(1);\n    }\n  }\n\n  /**\n   * @notice Converts bytes to uint256.\n   * @param bs byte[] data\n   * @param start offset into byte data to convert\n   * @return uint256 data\n   */\n  function getUint256FromBytes(bytes memory bs, uint256 start) internal pure returns (uint256) {\n    return uint256(getBytes32FromBytes(bs, start));\n  }\n\n  /**\n   * @notice Converts bytes to bytes32.\n   * @param bs byte[] data\n   * @param start offset into byte data to convert\n   * @return bytes32 data\n   */\n  function getBytes32FromBytes(bytes memory bs, uint256 start) internal pure returns (bytes32) {\n    require(bs.length >= start.add(32), \"slicing out of range\");\n    bytes32 x;\n    assembly {\n      x := mload(add(bs, add(start, 32)))\n    }\n    return x;\n  }\n}\n"},{"file_path":"lib/openzeppelin-contracts8/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"},{"file_path":"lib/openzeppelin-contracts8/contracts/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"contracts-0.8/common/interfaces/IStableToken.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.7 <0.8.20;\n\n/**\n * @title This interface describes the functions specific to Celo Stable Tokens, and in the\n * absence of interface inheritance is intended as a companion to IERC20.sol and ICeloToken.sol.\n */\ninterface IStableToken {\n  function transfer(address, uint256) external returns (bool);\n\n  function mint(address, uint256) external returns (bool);\n\n  function burn(uint256) external returns (bool);\n\n  function setInflationParameters(uint256, uint256) external;\n\n  function valueToUnits(uint256) external view returns (uint256);\n\n  function unitsToValue(uint256) external view returns (uint256);\n\n  function getInflationParameters() external view returns (uint256, uint256, uint256, uint256);\n\n  // NOTE: duplicated with IERC20.sol, remove once interface inheritance is supported.\n  function balanceOf(address) external view returns (uint256);\n}\n"},{"file_path":"contracts/governance/interfaces/IEpochRewards.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IEpochRewards {\n  function updateTargetVotingYield() external;\n  function calculateTargetEpochRewards() external view returns (uint256, uint256, uint256, uint256);\n  function getTargetVotingYieldParameters() external view returns (uint256, uint256, uint256);\n  function getRewardsMultiplierParameters() external view returns (uint256, uint256, uint256);\n  function getCommunityRewardFraction() external view returns (uint256);\n  function getCarbonOffsettingFraction() external view returns (uint256);\n  function getTargetVotingGoldFraction() external view returns (uint256);\n  function getRewardsMultiplier() external view returns (uint256);\n  function carbonOffsettingPartner() external view returns (address);\n}\n"},{"file_path":"contracts/common/interfaces/IFeeCurrencyWhitelist.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IFeeCurrencyWhitelist {\n  function initialize() external;\n  function addToken(address) external;\n  function getWhitelist() external view returns (address[] memory);\n}\n"},{"file_path":"lib/openzeppelin-contracts8/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"},{"file_path":"contracts/governance/interfaces/IValidators.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IValidators {\n  function registerValidator(bytes calldata) external returns (bool);\n  function registerValidatorNoBls(bytes calldata ecdsaPublicKey) external returns (bool);\n  function deregisterValidator(uint256) external returns (bool);\n  function affiliate(address) external returns (bool);\n  function deaffiliate() external returns (bool);\n  function registerValidatorGroup(uint256) external returns (bool);\n  function deregisterValidatorGroup(uint256) external returns (bool);\n  function addMember(address) external returns (bool);\n  function addFirstMember(address, address, address) external returns (bool);\n  function removeMember(address) external returns (bool);\n  function reorderMember(address, address, address) external returns (bool);\n  function updateCommission() external;\n  function setNextCommissionUpdate(uint256) external;\n  function updateVoterRewardCommission() external;\n  function setNextVoterRewardCommissionUpdate(uint256) external;\n  function resetSlashingMultiplier() external;\n\n  // only owner\n  function setCommissionUpdateDelay(uint256) external;\n  function setMaxVoterRewardCommission(uint256) external;\n  function setMaxGroupSize(uint256) external returns (bool);\n  function setMembershipHistoryLength(uint256) external returns (bool);\n  function setGroupLockedGoldRequirements(uint256, uint256) external returns (bool);\n  function setValidatorLockedGoldRequirements(uint256, uint256) external returns (bool);\n  function setSlashingMultiplierResetPeriod(uint256) external;\n\n  // only registered contract\n  function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool);\n  function mintStableToEpochManager(uint256 amount) external;\n\n  // only slasher\n  function forceDeaffiliateIfValidator(address) external;\n  function halveSlashingMultiplier(address) external;\n\n  // view functions\n  function maxGroupSize() external view returns (uint256);\n  function getCommissionUpdateDelay() external view returns (uint256);\n  function getVoterRewardCommission(address) external view returns (uint256, uint256, uint256);\n  function maxVoterRewardCommission() external view returns (uint256);\n  function maxVoterRewardCommissionLastReducedBlock() external view returns (uint256);\n  function getMembershipHistory(\n    address\n  ) external view returns (uint256[] memory, address[] memory, uint256, uint256);\n  function getAccountLockedGoldRequirement(address) external view returns (uint256);\n  function meetsAccountLockedGoldRequirements(address) external view returns (bool);\n  function getValidator(\n    address account\n  ) external view returns (bytes memory, bytes memory, address, uint256, address);\n  function getValidatorsGroup(address account) external view returns (address affiliation);\n  function getValidatorGroup(\n    address\n  )\n    external\n    view\n    returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256);\n  function getGroupNumMembers(address) external view returns (uint256);\n  function getTopGroupValidators(address, uint256) external view returns (address[] memory);\n  function getTopGroupValidatorsAccounts(address, uint256) external view returns (address[] memory);\n  function getGroupsNumMembers(\n    address[] calldata accounts\n  ) external view returns (uint256[] memory);\n  function getNumRegisteredValidators() external view returns (uint256);\n  function groupMembershipInEpoch(address, uint256, uint256) external view returns (address);\n\n  function getValidatorLockedGoldRequirements() external view returns (uint256, uint256);\n  function getGroupLockedGoldRequirements() external view returns (uint256, uint256);\n  function getRegisteredValidators() external view returns (address[] memory);\n  function getRegisteredValidatorGroups() external view returns (address[] memory);\n  function isValidatorGroup(address) external view returns (bool);\n  function isValidator(address) external view returns (bool);\n  function getValidatorGroupSlashingMultiplier(address) external view returns (uint256);\n  function getMembershipInLastEpoch(address) external view returns (address);\n  function getMembershipInLastEpochFromSigner(address) external view returns (address);\n  function computeEpochReward(\n    address account,\n    uint256 score,\n    uint256 maxPayment\n  ) external view returns (uint256);\n  function getMembershipHistoryLength() external view returns (uint256);\n}\n"},{"file_path":"contracts-0.8/common/UsingRegistry.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.0 <0.8.20;\n\n// Note: This is not an exact copy of UsingRegistry or UsingRegistryV2 in the contract's folder\n// because Mento's interfaces still don't support Solidity 0.8\n\nimport \"@openzeppelin/contracts8/access/Ownable.sol\";\nimport \"@openzeppelin/contracts8/token/ERC20/IERC20.sol\";\n\nimport \"../../contracts/common/interfaces/IRegistry.sol\";\nimport \"../../contracts/common/interfaces/IAccounts.sol\";\nimport \"../../contracts/common/interfaces/IEpochManager.sol\";\nimport \"../../contracts/common/interfaces/IFreezer.sol\";\nimport \"../../contracts/common/interfaces/ICeloUnreleasedTreasury.sol\";\nimport \"../../contracts/common/interfaces/IFeeCurrencyWhitelist.sol\";\nimport \"../../contracts/common/interfaces/IFeeHandlerSeller.sol\";\nimport \"../../contracts/common/interfaces/IEpochManager.sol\";\nimport \"../../contracts/governance/interfaces/IGovernance.sol\";\nimport \"../../contracts/governance/interfaces/ILockedGold.sol\";\nimport \"../../contracts/governance/interfaces/ILockedCelo.sol\";\nimport \"../../contracts/governance/interfaces/IValidators.sol\";\nimport \"../../contracts/governance/interfaces/IElection.sol\";\nimport \"../../contracts/governance/interfaces/IEpochRewards.sol\";\nimport \"../../contracts/stability/interfaces/ISortedOracles.sol\";\n\nimport \"./interfaces/IScoreReader.sol\";\n\ncontract UsingRegistry is Ownable {\n  // solhint-disable state-visibility\n  bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked(\"Accounts\"));\n  bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked(\"Attestations\"));\n  bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked(\"DowntimeSlasher\"));\n  bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID =\n    keccak256(abi.encodePacked(\"DoubleSigningSlasher\"));\n  bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked(\"Election\"));\n  bytes32 constant EPOCH_REWARDS_REGISTRY_ID = keccak256(abi.encodePacked(\"EpochRewards\"));\n  bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked(\"Exchange\"));\n  bytes32 constant FEE_CURRENCY_WHITELIST_REGISTRY_ID =\n    keccak256(abi.encodePacked(\"FeeCurrencyWhitelist\"));\n  bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked(\"Freezer\"));\n  bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked(\"GoldToken\"));\n  bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked(\"Governance\"));\n  bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID =\n    keccak256(abi.encodePacked(\"GovernanceSlasher\"));\n  bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked(\"LockedGold\"));\n  bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked(\"Reserve\"));\n  bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked(\"Random\"));\n  bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked(\"SortedOracles\"));\n  bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked(\"StableToken\"));\n  bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked(\"Validators\"));\n  bytes32 constant MENTOFEEHANDLERSELLER_REGISTRY_ID =\n    keccak256(abi.encodePacked(\"MentoFeeHandlerSeller\"));\n  bytes32 constant CELO_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked(\"CeloToken\"));\n  bytes32 constant LOCKED_CELO_REGISTRY_ID = keccak256(abi.encodePacked(\"LockedCelo\"));\n  bytes32 constant CELO_UNRELEASED_TREASURY_REGISTRY_ID =\n    keccak256(abi.encodePacked(\"CeloUnreleasedTreasury\"));\n  bytes32 constant EPOCH_MANAGER_ENABLER_REGISTRY_ID =\n    keccak256(abi.encodePacked(\"EpochManagerEnabler\"));\n  bytes32 constant EPOCH_MANAGER_REGISTRY_ID = keccak256(abi.encodePacked(\"EpochManager\"));\n  bytes32 constant SCORE_MANAGER_REGISTRY_ID = keccak256(abi.encodePacked(\"ScoreManager\"));\n  // solhint-enable state-visibility\n\n  IRegistry public registry;\n\n  event RegistrySet(address indexed registryAddress);\n\n  modifier onlyRegisteredContract(bytes32 identifierHash) {\n    require(registry.getAddressForOrDie(identifierHash) == msg.sender, \"only registered contract\");\n    _;\n  }\n\n  modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) {\n    require(registry.isOneOf(identifierHashes, msg.sender), \"only registered contracts\");\n    _;\n  }\n\n  /**\n   * @notice Updates the address pointing to a Registry contract.\n   * @param registryAddress The address of a registry contract for routing to other contracts.\n   */\n  function setRegistry(address registryAddress) public onlyOwner {\n    require(registryAddress != address(0), \"Cannot register the null address\");\n    registry = IRegistry(registryAddress);\n    emit RegistrySet(registryAddress);\n  }\n\n  function getGoldToken() internal view returns (IERC20) {\n    return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));\n  }\n\n  function getCeloToken() internal view returns (IERC20) {\n    return IERC20(registry.getAddressForOrDie(CELO_TOKEN_REGISTRY_ID));\n  }\n\n  function getFreezer() internal view returns (IFreezer) {\n    return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID));\n  }\n\n  function getSortedOracles() internal view returns (ISortedOracles) {\n    return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID));\n  }\n\n  function getFeeCurrencyWhitelist() internal view returns (IFeeCurrencyWhitelist) {\n    return IFeeCurrencyWhitelist(registry.getAddressForOrDie(FEE_CURRENCY_WHITELIST_REGISTRY_ID));\n  }\n\n  function getLockedGold() internal view returns (ILockedGold) {\n    return ILockedGold(registry.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID));\n  }\n\n  function getLockedCelo() internal view returns (ILockedCelo) {\n    return ILockedCelo(registry.getAddressForOrDie(LOCKED_CELO_REGISTRY_ID));\n  }\n\n  // Current version of Mento doesn't support 0.8\n  function getStableToken() internal view returns (address) {\n    return registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID);\n  }\n\n  function getMentoFeeHandlerSeller() internal view returns (IFeeHandlerSeller) {\n    return IFeeHandlerSeller(registry.getAddressForOrDie(MENTOFEEHANDLERSELLER_REGISTRY_ID));\n  }\n\n  function getAccounts() internal view returns (IAccounts) {\n    return IAccounts(registry.getAddressForOrDie(ACCOUNTS_REGISTRY_ID));\n  }\n\n  function getValidators() internal view returns (IValidators) {\n    return IValidators(registry.getAddressForOrDie(VALIDATORS_REGISTRY_ID));\n  }\n\n  function getElection() internal view returns (IElection) {\n    return IElection(registry.getAddressForOrDie(ELECTION_REGISTRY_ID));\n  }\n\n  function getEpochRewards() internal view returns (IEpochRewards) {\n    return IEpochRewards(registry.getAddressForOrDie(EPOCH_REWARDS_REGISTRY_ID));\n  }\n\n  function getGovernance() internal view returns (IGovernance) {\n    return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID));\n  }\n\n  function getCeloUnreleasedTreasury() internal view returns (ICeloUnreleasedTreasury) {\n    return\n      ICeloUnreleasedTreasury(registry.getAddressForOrDie(CELO_UNRELEASED_TREASURY_REGISTRY_ID));\n  }\n\n  function getEpochManager() internal view returns (IEpochManager) {\n    return IEpochManager(registry.getAddressForOrDie(EPOCH_MANAGER_REGISTRY_ID));\n  }\n\n  function getScoreReader() internal view returns (IScoreReader) {\n    return IScoreReader(registry.getAddressForOrDie(SCORE_MANAGER_REGISTRY_ID));\n  }\n}\n"},{"file_path":"contracts/common/FixidityLib.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\n/**\n * @title FixidityLib\n * @author Gadi Guy, Alberto Cuesta Canada\n * @notice This library provides fixed point arithmetic with protection against\n * overflow.\n * All operations are done with uint256 and the operands must have been created\n * with any of the newFrom* functions, which shift the comma digits() to the\n * right and check for limits, or with wrap() which expects a number already\n * in the internal representation of a fraction.\n * When using this library be sure to use maxNewFixed() as the upper limit for\n * creation of fixed point numbers.\n * @dev All contained functions are pure and thus marked internal to be inlined\n * on consuming contracts at compile time for gas efficiency.\n */\nlibrary FixidityLib {\n  struct Fraction {\n    uint256 value;\n  }\n\n  uint256 private constant FIXED1_UINT = 1000000000000000000000000;\n\n  /**\n   * @notice Number of positions that the comma is shifted to the right.\n   */\n  function digits() internal pure returns (uint8) {\n    return 24;\n  }\n\n  /**\n   * @notice This is 1 in the fixed point units used in this library.\n   * @dev Test fixed1() equals 10^digits()\n   * Hardcoded to 24 digits.\n   */\n  function fixed1() internal pure returns (Fraction memory) {\n    return Fraction(FIXED1_UINT);\n  }\n\n  /**\n   * @notice Wrap a uint256 that represents a 24-decimal fraction in a Fraction\n   * struct.\n   * @param x Number that already represents a 24-decimal fraction.\n   * @return A Fraction struct with contents x.\n   */\n  function wrap(uint256 x) internal pure returns (Fraction memory) {\n    return Fraction(x);\n  }\n\n  /**\n   * @notice Unwraps the uint256 inside of a Fraction struct.\n   */\n  function unwrap(Fraction memory x) internal pure returns (uint256) {\n    return x.value;\n  }\n\n  /**\n   * @notice The amount of decimals lost on each multiplication operand.\n   * @dev Test mulPrecision() equals sqrt(fixed1)\n   */\n  function mulPrecision() internal pure returns (uint256) {\n    return 1000000000000;\n  }\n\n  /**\n   * @notice Maximum value that can be converted to fixed point. Optimize for deployment.\n   * @dev\n   * Test maxNewFixed() equals maxUint256() / fixed1()\n   */\n  function maxNewFixed() internal pure returns (uint256) {\n    return 115792089237316195423570985008687907853269984665640564;\n  }\n\n  /**\n   * @notice Converts a uint256 to fixed point Fraction\n   * @dev Test newFixed(0) returns 0\n   * Test newFixed(1) returns fixed1()\n   * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1()\n   * Test newFixed(maxNewFixed()+1) fails\n   */\n  function newFixed(uint256 x) internal pure returns (Fraction memory) {\n    require(x <= maxNewFixed(), \"can't create fixidity number larger than maxNewFixed()\");\n    return Fraction(x * FIXED1_UINT);\n  }\n\n  /**\n   * @notice Converts a uint256 in the fixed point representation of this\n   * library to a non decimal. All decimal digits will be truncated.\n   */\n  function fromFixed(Fraction memory x) internal pure returns (uint256) {\n    return x.value / FIXED1_UINT;\n  }\n\n  /**\n   * @notice Converts two uint256 representing a fraction to fixed point units,\n   * equivalent to multiplying dividend and divisor by 10^digits().\n   * @param numerator numerator must be <= maxNewFixed()\n   * @param denominator denominator must be <= maxNewFixed() and denominator can't be 0\n   * @dev\n   * Test newFixedFraction(1,0) fails\n   * Test newFixedFraction(0,1) returns 0\n   * Test newFixedFraction(1,1) returns fixed1()\n   * Test newFixedFraction(1,fixed1()) returns 1\n   */\n  function newFixedFraction(\n    uint256 numerator,\n    uint256 denominator\n  ) internal pure returns (Fraction memory) {\n    Fraction memory convertedNumerator = newFixed(numerator);\n    Fraction memory convertedDenominator = newFixed(denominator);\n    return divide(convertedNumerator, convertedDenominator);\n  }\n\n  /**\n   * @notice Returns the integer part of a fixed point number.\n   * @dev\n   * Test integer(0) returns 0\n   * Test integer(fixed1()) returns fixed1()\n   * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1()\n   */\n  function integer(Fraction memory x) internal pure returns (Fraction memory) {\n    return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow\n  }\n\n  /**\n   * @notice Returns the fractional part of a fixed point number.\n   * In the case of a negative number the fractional is also negative.\n   * @dev\n   * Test fractional(0) returns 0\n   * Test fractional(fixed1()) returns 0\n   * Test fractional(fixed1()-1) returns 10^24-1\n   */\n  function fractional(Fraction memory x) internal pure returns (Fraction memory) {\n    return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow\n  }\n\n  /**\n   * @notice x+y.\n   * @dev The maximum value that can be safely used as an addition operator is defined as\n   * maxFixedAdd = maxUint256()-1 / 2, or\n   * 57896044618658097711785492504343953926634992332820282019728792003956564819967.\n   * Test add(maxFixedAdd,maxFixedAdd) equals maxFixedAdd + maxFixedAdd\n   * Test add(maxFixedAdd+1,maxFixedAdd+1) throws\n   */\n  function add(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    uint256 z = x.value + y.value;\n    require(z >= x.value, \"add overflow detected\");\n    return Fraction(z);\n  }\n\n  /**\n   * @notice x-y.\n   * @dev\n   * Test subtract(6, 10) fails\n   */\n  function subtract(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    require(x.value >= y.value, \"substraction underflow detected\");\n    return Fraction(x.value - y.value);\n  }\n\n  /**\n   * @notice x*y. If any of the operators is higher than the max multiplier value it\n   * might overflow.\n   * @dev The maximum value that can be safely used as a multiplication operator\n   * (maxFixedMul) is calculated as sqrt(maxUint256()*fixed1()),\n   * or 340282366920938463463374607431768211455999999999999\n   * Test multiply(0,0) returns 0\n   * Test multiply(maxFixedMul,0) returns 0\n   * Test multiply(0,maxFixedMul) returns 0\n   * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) returns fixed1()\n   * Test multiply(maxFixedMul,maxFixedMul) is around maxUint256()\n   * Test multiply(maxFixedMul+1,maxFixedMul+1) fails\n   */\n  function multiply(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    if (x.value == 0 || y.value == 0) return Fraction(0);\n    if (y.value == FIXED1_UINT) return x;\n    if (x.value == FIXED1_UINT) return y;\n\n    // Separate into integer and fractional parts\n    // x = x1 + x2, y = y1 + y2\n    uint256 x1 = integer(x).value / FIXED1_UINT;\n    uint256 x2 = fractional(x).value;\n    uint256 y1 = integer(y).value / FIXED1_UINT;\n    uint256 y2 = fractional(y).value;\n\n    // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2)\n    uint256 x1y1 = x1 * y1;\n    if (x1 != 0) require(x1y1 / x1 == y1, \"overflow x1y1 detected\");\n\n    // x1y1 needs to be multiplied back by fixed1\n    // solium-disable-next-line mixedcase\n    uint256 fixed_x1y1 = x1y1 * FIXED1_UINT;\n    if (x1y1 != 0) require(fixed_x1y1 / x1y1 == FIXED1_UINT, \"overflow x1y1 * fixed1 detected\");\n    x1y1 = fixed_x1y1;\n\n    uint256 x2y1 = x2 * y1;\n    if (x2 != 0) require(x2y1 / x2 == y1, \"overflow x2y1 detected\");\n\n    uint256 x1y2 = x1 * y2;\n    if (x1 != 0) require(x1y2 / x1 == y2, \"overflow x1y2 detected\");\n\n    x2 = x2 / mulPrecision();\n    y2 = y2 / mulPrecision();\n    uint256 x2y2 = x2 * y2;\n    if (x2 != 0) require(x2y2 / x2 == y2, \"overflow x2y2 detected\");\n\n    // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1();\n    Fraction memory result = Fraction(x1y1);\n    result = add(result, Fraction(x2y1)); // Add checks for overflow\n    result = add(result, Fraction(x1y2)); // Add checks for overflow\n    result = add(result, Fraction(x2y2)); // Add checks for overflow\n    return result;\n  }\n\n  /**\n   * @notice 1/x\n   * @dev\n   * Test reciprocal(0) fails\n   * Test reciprocal(fixed1()) returns fixed1()\n   * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated\n   * Test reciprocal(1+fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated\n   * Test reciprocal(newFixedFraction(1, 1e24)) returns newFixed(1e24)\n   */\n  function reciprocal(Fraction memory x) internal pure returns (Fraction memory) {\n    require(x.value != 0, \"can't call reciprocal(0)\");\n    return Fraction((FIXED1_UINT * FIXED1_UINT) / x.value); // Can't overflow\n  }\n\n  /**\n   * @notice x/y. If the dividend is higher than the max dividend value, it\n   * might overflow. You can use multiply(x,reciprocal(y)) instead.\n   * @dev The maximum value that can be safely used as a dividend (maxNewFixed) is defined as\n   * divide(maxNewFixed,newFixedFraction(1,fixed1())) is around maxUint256().\n   * This yields the value 115792089237316195423570985008687907853269984665640564.\n   * Test maxNewFixed equals maxUint256()/fixed1()\n   * Test divide(maxNewFixed,1) equals maxNewFixed*(fixed1)\n   * Test divide(maxNewFixed+1,multiply(mulPrecision(),mulPrecision())) throws\n   * Test divide(fixed1(),0) fails\n   * Test divide(maxNewFixed,1) = maxNewFixed*(10^digits())\n   * Test divide(maxNewFixed+1,1) throws\n   */\n  function divide(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    require(y.value != 0, \"can't divide by 0\");\n    uint256 X = x.value * FIXED1_UINT;\n    require(X / FIXED1_UINT == x.value, \"overflow at divide\");\n    return Fraction(X / y.value);\n  }\n\n  /**\n   * @notice x > y\n   */\n  function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value > y.value;\n  }\n\n  /**\n   * @notice x >= y\n   */\n  function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value >= y.value;\n  }\n\n  /**\n   * @notice x < y\n   */\n  function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value < y.value;\n  }\n\n  /**\n   * @notice x <= y\n   */\n  function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value <= y.value;\n  }\n\n  /**\n   * @notice x == y\n   */\n  function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value == y.value;\n  }\n\n  /**\n   * @notice x <= 1\n   */\n  function isProperFraction(Fraction memory x) internal pure returns (bool) {\n    return lte(x, fixed1());\n  }\n}\n"},{"file_path":"contracts-0.8/common/linkedlists/AddressLinkedList.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.0 <0.8.20;\n\nimport \"@openzeppelin/contracts8/utils/math/SafeMath.sol\";\n\nimport \"./LinkedList.sol\";\n\n/**\n * @title Maintains a doubly linked list keyed by address.\n * @dev Following the `next` pointers will lead you to the head, rather than the tail.\n */\nlibrary AddressLinkedList {\n  using LinkedList for LinkedList.List;\n  using SafeMath for uint256;\n  /**\n   * @notice Inserts an element into a doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The key of the element to insert.\n   * @param previousKey The key of the element that comes before the element to insert.\n   * @param nextKey The key of the element that comes after the element to insert.\n   */\n  function insert(\n    LinkedList.List storage list,\n    address key,\n    address previousKey,\n    address nextKey\n  ) public {\n    list.insert(toBytes(key), toBytes(previousKey), toBytes(nextKey));\n  }\n\n  /**\n   * @notice Inserts an element at the end of the doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The key of the element to insert.\n   */\n  function push(LinkedList.List storage list, address key) public {\n    list.insert(toBytes(key), bytes32(0), list.tail);\n  }\n\n  /**\n   * @notice Removes an element from the doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The key of the element to remove.\n   */\n  function remove(LinkedList.List storage list, address key) public {\n    list.remove(toBytes(key));\n  }\n\n  /**\n   * @notice Updates an element in the list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The element key.\n   * @param previousKey The key of the element that comes before the updated element.\n   * @param nextKey The key of the element that comes after the updated element.\n   */\n  function update(\n    LinkedList.List storage list,\n    address key,\n    address previousKey,\n    address nextKey\n  ) public {\n    list.update(toBytes(key), toBytes(previousKey), toBytes(nextKey));\n  }\n\n  /**\n   * @notice Returns whether or not a particular key is present in the sorted list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The element key.\n   * @return Whether or not the key is in the sorted list.\n   */\n  function contains(LinkedList.List storage list, address key) public view returns (bool) {\n    return list.elements[toBytes(key)].exists;\n  }\n\n  /**\n   * @notice Returns the N greatest elements of the list.\n   * @param list A storage pointer to the underlying list.\n   * @param n The number of elements to return.\n   * @return The keys of the greatest elements.\n   * @dev Reverts if n is greater than the number of elements in the list.\n   */\n  function headN(LinkedList.List storage list, uint256 n) public view returns (address[] memory) {\n    bytes32[] memory byteKeys = list.headN(n);\n    address[] memory keys = new address[](n);\n    for (uint256 i = 0; i < n; i = i.add(1)) {\n      keys[i] = toAddress(byteKeys[i]);\n    }\n    return keys;\n  }\n\n  /**\n   * @notice Gets all element keys from the doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @return All element keys from head to tail.\n   */\n  function getKeys(LinkedList.List storage list) public view returns (address[] memory) {\n    return headN(list, list.numElements);\n  }\n\n  function toBytes(address a) public pure returns (bytes32) {\n    return bytes32(uint256(uint160(a)) << 96);\n  }\n\n  function toAddress(bytes32 b) public pure returns (address) {\n    return address(uint160(uint256(b) >> 96));\n  }\n}\n"},{"file_path":"contracts/governance/interfaces/ILockedGold.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface ILockedGold {\n  function lock() external payable;\n  function incrementNonvotingAccountBalance(address, uint256) external;\n  function decrementNonvotingAccountBalance(address, uint256) external;\n\n  function unlock(uint256) external;\n  function relock(uint256, uint256) external;\n  function withdraw(uint256) external;\n  function slash(\n    address account,\n    uint256 penalty,\n    address reporter,\n    uint256 reward,\n    address[] calldata lessers,\n    address[] calldata greaters,\n    uint256[] calldata indices\n  ) external;\n  function addSlasher(string calldata slasherIdentifier) external;\n\n  function getAccountTotalLockedGold(address) external view returns (uint256);\n  function getTotalLockedGold() external view returns (uint256);\n  function getPendingWithdrawals(\n    address\n  ) external view returns (uint256[] memory, uint256[] memory);\n  function getPendingWithdrawal(\n    address account,\n    uint256 index\n  ) external view returns (uint256, uint256);\n  function getTotalPendingWithdrawals(address) external view returns (uint256);\n  function isSlasher(address) external view returns (bool);\n\n  function getAccountTotalDelegatedFraction(address account) external view returns (uint256);\n\n  function getAccountTotalGovernanceVotingPower(address account) external view returns (uint256);\n  function unlockingPeriod() external view returns (uint256);\n  function getAccountNonvotingLockedGold(address account) external view returns (uint256);\n}\n"},{"file_path":"contracts-0.8/common/linkedlists/LinkedList.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.0 <0.8.20;\n\nimport \"@openzeppelin/contracts8/utils/math/SafeMath.sol\";\n\n/**\n * @title Maintains a doubly linked list keyed by bytes32.\n * @dev Following the `next` pointers will lead you to the head, rather than the tail.\n */\nlibrary LinkedList {\n  using SafeMath for uint256;\n\n  struct Element {\n    bytes32 previousKey;\n    bytes32 nextKey;\n    bool exists;\n  }\n\n  struct List {\n    bytes32 head;\n    bytes32 tail;\n    uint256 numElements;\n    mapping(bytes32 => Element) elements;\n  }\n\n  /**\n   * @notice Inserts an element into a doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The key of the element to insert.\n   * @param previousKey The key of the element that comes before the element to insert.\n   * @param nextKey The key of the element that comes after the element to insert.\n   */\n  function insert(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) internal {\n    require(key != bytes32(0), \"Key must be defined\");\n    require(!contains(list, key), \"Can't insert an existing element\");\n    require(\n      previousKey != key && nextKey != key,\n      \"Key cannot be the same as previousKey or nextKey\"\n    );\n\n    Element storage element = list.elements[key];\n    element.exists = true;\n\n    if (list.numElements == 0) {\n      list.tail = key;\n      list.head = key;\n    } else {\n      require(\n        previousKey != bytes32(0) || nextKey != bytes32(0),\n        \"Either previousKey or nextKey must be defined\"\n      );\n\n      element.previousKey = previousKey;\n      element.nextKey = nextKey;\n\n      if (previousKey != bytes32(0)) {\n        require(\n          contains(list, previousKey),\n          \"If previousKey is defined, it must exist in the list\"\n        );\n        Element storage previousElement = list.elements[previousKey];\n        require(previousElement.nextKey == nextKey, \"previousKey must be adjacent to nextKey\");\n        previousElement.nextKey = key;\n      } else {\n        list.tail = key;\n      }\n\n      if (nextKey != bytes32(0)) {\n        require(contains(list, nextKey), \"If nextKey is defined, it must exist in the list\");\n        Element storage nextElement = list.elements[nextKey];\n        require(nextElement.previousKey == previousKey, \"previousKey must be adjacent to nextKey\");\n        nextElement.previousKey = key;\n      } else {\n        list.head = key;\n      }\n    }\n\n    list.numElements = list.numElements.add(1);\n  }\n\n  /**\n   * @notice Inserts an element at the tail of the doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The key of the element to insert.\n   */\n  function push(List storage list, bytes32 key) internal {\n    insert(list, key, bytes32(0), list.tail);\n  }\n\n  /**\n   * @notice Removes an element from the doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The key of the element to remove.\n   */\n  function remove(List storage list, bytes32 key) internal {\n    Element storage element = list.elements[key];\n    require(key != bytes32(0) && contains(list, key), \"key not in list\");\n    if (element.previousKey != bytes32(0)) {\n      Element storage previousElement = list.elements[element.previousKey];\n      previousElement.nextKey = element.nextKey;\n    } else {\n      list.tail = element.nextKey;\n    }\n\n    if (element.nextKey != bytes32(0)) {\n      Element storage nextElement = list.elements[element.nextKey];\n      nextElement.previousKey = element.previousKey;\n    } else {\n      list.head = element.previousKey;\n    }\n\n    delete list.elements[key];\n    list.numElements = list.numElements.sub(1);\n  }\n\n  /**\n   * @notice Updates an element in the list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The element key.\n   * @param previousKey The key of the element that comes before the updated element.\n   * @param nextKey The key of the element that comes after the updated element.\n   */\n  function update(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) internal {\n    require(\n      key != bytes32(0) && key != previousKey && key != nextKey && contains(list, key),\n      \"key on in list\"\n    );\n    remove(list, key);\n    insert(list, key, previousKey, nextKey);\n  }\n\n  /**\n   * @notice Returns whether or not a particular key is present in the sorted list.\n   * @param list A storage pointer to the underlying list.\n   * @param key The element key.\n   * @return Whether or not the key is in the sorted list.\n   */\n  function contains(List storage list, bytes32 key) internal view returns (bool) {\n    return list.elements[key].exists;\n  }\n\n  /**\n   * @notice Returns the keys of the N elements at the head of the list.\n   * @param list A storage pointer to the underlying list.\n   * @param n The number of elements to return.\n   * @return The keys of the N elements at the head of the list.\n   * @dev Reverts if n is greater than the number of elements in the list.\n   */\n  function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) {\n    require(n <= list.numElements, \"not enough elements\");\n    bytes32[] memory keys = new bytes32[](n);\n    bytes32 key = list.head;\n    for (uint256 i = 0; i < n; i = i.add(1)) {\n      keys[i] = key;\n      key = list.elements[key].previousKey;\n    }\n    return keys;\n  }\n\n  /**\n   * @notice Gets all element keys from the doubly linked list.\n   * @param list A storage pointer to the underlying list.\n   * @return All element keys from head to tail.\n   */\n  function getKeys(List storage list) internal view returns (bytes32[] memory) {\n    return headN(list, list.numElements);\n  }\n}\n"},{"file_path":"contracts/common/interfaces/IFreezer.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IFreezer {\n  function freeze(address target) external;\n  function unfreeze(address target) external;\n  function isFrozen(address) external view returns (bool);\n}\n"},{"file_path":"contracts/common/interfaces/ICeloVersionedContract.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface ICeloVersionedContract {\n  /**\n   * @notice Returns the storage, major, minor, and patch version of the contract.\n   * @return Storage version of the contract.\n   * @return Major version of the contract.\n   * @return Minor version of the contract.\n   * @return Patch version of the contract.\n   */\n  function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256);\n}\n"},{"file_path":"contracts/common/libraries/ReentrancyGuard.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.8.20;\n\n/**\n * @title Helps contracts guard against reentrancy attacks.\n * @author Remco Bloemen <remco@2π.com>, Eenae <alexey@mixbytes.io>\n * @dev If you mark a function `nonReentrant`, you should also\n * mark it `external`.\n */\ncontract ReentrancyGuard {\n  /// @dev counter to allow mutex lock with only one SSTORE operation\n  uint256 private _guardCounter;\n\n  /**\n   * @dev Prevents a contract from calling itself, directly or indirectly.\n   * Calling a `nonReentrant` function from another `nonReentrant`\n   * function is not supported. It is possible to prevent this from happening\n   * by making the `nonReentrant` function external, and make it call a\n   * `private` function that does the actual work.\n   */\n  modifier nonReentrant() {\n    _guardCounter += 1;\n    uint256 localCounter = _guardCounter;\n    _;\n    require(localCounter == _guardCounter, \"reentrant call\");\n  }\n\n  constructor() public {\n    // The counter starts at one to prevent changing it from zero to a non-zero\n    // value, which is a more expensive operation.\n    _guardCounter = 1;\n  }\n}\n"},{"file_path":"contracts/stability/interfaces/ISortedOracles.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface ISortedOracles {\n  function addOracle(address, address) external;\n  function removeOracle(address, address, uint256) external;\n  function report(address, uint256, address, address) external;\n  function removeExpiredReports(address, uint256) external;\n  function isOldestReportExpired(address token) external view returns (bool, address);\n  function numRates(address) external view returns (uint256);\n  function medianRate(address) external view returns (uint256, uint256);\n  function numTimestamps(address) external view returns (uint256);\n  function medianTimestamp(address) external view returns (uint256);\n}\n"},{"file_path":"lib/openzeppelin-contracts8/contracts/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n                // The surrounding unchecked block does not change this fact.\n                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1, \"Math: mulDiv overflow\");\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10 ** 64) {\n                value /= 10 ** 64;\n                result += 64;\n            }\n            if (value >= 10 ** 32) {\n                value /= 10 ** 32;\n                result += 32;\n            }\n            if (value >= 10 ** 16) {\n                value /= 10 ** 16;\n                result += 16;\n            }\n            if (value >= 10 ** 8) {\n                value /= 10 ** 8;\n                result += 8;\n            }\n            if (value >= 10 ** 4) {\n                value /= 10 ** 4;\n                result += 4;\n            }\n            if (value >= 10 ** 2) {\n                value /= 10 ** 2;\n                result += 2;\n            }\n            if (value >= 10 ** 1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);\n        }\n    }\n}\n"},{"file_path":"contracts/governance/interfaces/ILockedCelo.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface ILockedCelo {\n  function lock() external payable;\n  function incrementNonvotingAccountBalance(address, uint256) external;\n  function decrementNonvotingAccountBalance(address, uint256) external;\n\n  function unlock(uint256) external;\n  function relock(uint256, uint256) external;\n  function withdraw(uint256) external;\n  function slash(\n    address account,\n    uint256 penalty,\n    address reporter,\n    uint256 reward,\n    address[] calldata lessers,\n    address[] calldata greaters,\n    uint256[] calldata indices\n  ) external;\n  function addSlasher(string calldata slasherIdentifier) external;\n\n  function getAccountNonvotingLockedGold(address account) external view returns (uint256);\n  function getAccountTotalLockedCelo(address) external view returns (uint256);\n  function getTotalLockedCelo() external view returns (uint256);\n  function getPendingWithdrawals(\n    address\n  ) external view returns (uint256[] memory, uint256[] memory);\n  function getPendingWithdrawal(\n    address account,\n    uint256 index\n  ) external view returns (uint256, uint256);\n  function getTotalPendingWithdrawals(address) external view returns (uint256);\n  function isSlasher(address) external view returns (bool);\n\n  function getAccountTotalDelegatedFraction(address account) external view returns (uint256);\n\n  function getAccountTotalGovernanceVotingPower(address account) external view returns (uint256);\n  function unlockingPeriod() external view returns (uint256);\n  function getAccountNonvotingLockedCelo(address account) external view returns (uint256);\n\n  function getAccountTotalLockedGold(address account) external view returns (uint256);\n}\n"},{"file_path":"contracts/common/interfaces/IFeeHandlerSeller.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IFeeHandlerSeller {\n  function sell(\n    address sellTokenAddress,\n    address buyTokenAddress,\n    uint256 amount,\n    uint256 minAmount\n  ) external returns (uint256);\n  // in case some funds need to be returned or moved to another contract\n  function transfer(address token, uint256 amount, address to) external returns (bool);\n}\n"},{"file_path":"contracts/governance/interfaces/IElection.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IElection {\n  function vote(\n    address group,\n    uint256 value,\n    address lesser,\n    address greater\n  ) external returns (bool);\n  function activate(address group) external returns (bool);\n  function revokeActive(\n    address group,\n    uint256 value,\n    address lesser,\n    address greater,\n    uint256 index\n  ) external returns (bool);\n  function revokeAllActive(\n    address group,\n    address lesser,\n    address greater,\n    uint256 index\n  ) external returns (bool);\n  function revokePending(\n    address group,\n    uint256 value,\n    address lesser,\n    address greater,\n    uint256 index\n  ) external returns (bool);\n  function markGroupIneligible(address group) external;\n  function markGroupEligible(address group, address lesser, address greater) external;\n  function allowedToVoteOverMaxNumberOfGroups(address account) external returns (bool);\n  function forceDecrementVotes(\n    address account,\n    uint256 value,\n    address[] calldata lessers,\n    address[] calldata greaters,\n    uint256[] calldata indices\n  ) external returns (uint256);\n  function setAllowedToVoteOverMaxNumberOfGroups(bool flag) external;\n\n  // only owner\n  function setElectableValidators(uint256 min, uint256 max) external returns (bool);\n  function setMaxNumGroupsVotedFor(uint256 _maxNumGroupsVotedFor) external returns (bool);\n  function setElectabilityThreshold(uint256 threshold) external returns (bool);\n\n  // only VM\n  function distributeEpochRewards(\n    address group,\n    uint256 value,\n    address lesser,\n    address greater\n  ) external;\n\n  // view functions\n  function electValidatorSigners() external view returns (address[] memory);\n  function electValidatorAccounts() external view returns (address[] memory);\n  function electNValidatorSigners(\n    uint256 minElectableValidators,\n    uint256 maxElectableValidators\n  ) external view returns (address[] memory);\n  function electNValidatorAccounts(\n    uint256 minElectableValidators,\n    uint256 maxElectableValidators\n  ) external view returns (address[] memory);\n  function getElectableValidators() external view returns (uint256, uint256);\n  function getElectabilityThreshold() external view returns (uint256);\n  function getNumVotesReceivable(address group) external view returns (uint256);\n  function getTotalVotes() external view returns (uint256);\n  function getActiveVotes() external view returns (uint256);\n  function getTotalVotesByAccount(address account) external view returns (uint256);\n  function getPendingVotesForGroupByAccount(\n    address group,\n    address account\n  ) external view returns (uint256);\n  function getActiveVotesForGroupByAccount(\n    address group,\n    address account\n  ) external view returns (uint256);\n  function getTotalVotesForGroupByAccount(\n    address group,\n    address account\n  ) external view returns (uint256);\n  function getActiveVoteUnitsForGroupByAccount(\n    address group,\n    address account\n  ) external view returns (uint256);\n  function getTotalVotesForGroup(address group) external view returns (uint256);\n  function getActiveVotesForGroup(address group) external view returns (uint256);\n  function getPendingVotesForGroup(address group) external view returns (uint256);\n  function getGroupEligibility(address group) external view returns (bool);\n  function getGroupEpochRewardsBasedOnScore(\n    address group,\n    uint256 totalEpochRewards,\n    uint256 groupScore\n  ) external view returns (uint256);\n  function getGroupsVotedForByAccount(address account) external view returns (address[] memory);\n  function getEligibleValidatorGroups() external view returns (address[] memory);\n  function getTotalVotesForEligibleValidatorGroups()\n    external\n    view\n    returns (address[] memory, uint256[] memory);\n  function getCurrentValidatorSigners() external view returns (address[] memory);\n  function canReceiveVotes(address group, uint256 value) external view returns (bool);\n  function hasActivatablePendingVotes(address account, address group) external view returns (bool);\n  function validatorSignerAddressFromCurrentSet(uint256 index) external view returns (address);\n  function numberValidatorsInCurrentSet() external view returns (uint256);\n  function owner() external view returns (address);\n}\n"},{"file_path":"contracts/common/interfaces/IEpochManager.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IEpochManager {\n  function initializeSystem(\n    uint256 firstEpochNumber,\n    uint256 firstEpochBlock,\n    address[] calldata firstElected\n  ) external;\n  function startNextEpochProcess() external;\n  function finishNextEpochProcess(\n    address[] calldata groups,\n    address[] calldata lessers,\n    address[] calldata greaters\n  ) external;\n  function setToProcessGroups() external;\n  function processGroup(address group, address lesser, address greater) external;\n  function sendValidatorPayment(address) external;\n  function getCurrentEpoch() external view returns (uint256, uint256, uint256, uint256);\n  function getEpochByNumber(\n    uint256 epochNumber\n  ) external view returns (uint256, uint256, uint256, uint256);\n  function getEpochByBlockNumber(\n    uint256 blockNumber\n  ) external view returns (uint256, uint256, uint256, uint256);\n  function getEpochNumberOfBlock(uint256) external view returns (uint256);\n  function getCurrentEpochNumber() external view returns (uint256);\n  function numberOfElectedInCurrentSet() external view returns (uint256);\n  function getElectedAccounts() external view returns (address[] memory);\n  function getElectedAccountByIndex(uint256 index) external view returns (address);\n  function getElectedSigners() external view returns (address[] memory);\n  function getElectedSignerByIndex(uint256 index) external view returns (address);\n  function epochDuration() external view returns (uint256);\n  function firstKnownEpoch() external view returns (uint256);\n  function getEpochProcessingState()\n    external\n    view\n    returns (uint256, uint256, uint256, uint256, uint256);\n  function systemAlreadyInitialized() external view returns (bool);\n  function isBlocked() external view returns (bool);\n  function isTimeForNextEpoch() external view returns (bool);\n  function isOnEpochProcess() external view returns (bool);\n  function isEpochProcessingStarted() external view returns (bool);\n  function getFirstBlockAtEpoch(uint256) external view returns (uint256);\n  function getLastBlockAtEpoch(uint256) external view returns (uint256);\n}\n"},{"file_path":"lib/solidity-bytes-utils-8/contracts/BytesLib.sol","source_code":"// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá <goncalo.sa@consensys.net>\n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\n\nlibrary BytesLib {\n    function concat(\n        bytes memory _preBytes,\n        bytes memory _postBytes\n    )\n        internal\n        pure\n        returns (bytes memory)\n    {\n        bytes memory tempBytes;\n\n        assembly {\n            // Get a location of some free memory and store it in tempBytes as\n            // Solidity does for memory variables.\n            tempBytes := mload(0x40)\n\n            // Store the length of the first bytes array at the beginning of\n            // the memory for tempBytes.\n            let length := mload(_preBytes)\n            mstore(tempBytes, length)\n\n            // Maintain a memory counter for the current write location in the\n            // temp bytes array by adding the 32 bytes for the array length to\n            // the starting location.\n            let mc := add(tempBytes, 0x20)\n            // Stop copying when the memory counter reaches the length of the\n            // first bytes array.\n            let end := add(mc, length)\n\n            for {\n                // Initialize a copy counter to the start of the _preBytes data,\n                // 32 bytes into its memory.\n                let cc := add(_preBytes, 0x20)\n            } lt(mc, end) {\n                // Increase both counters by 32 bytes each iteration.\n                mc := add(mc, 0x20)\n                cc := add(cc, 0x20)\n            } {\n                // Write the _preBytes data into the tempBytes memory 32 bytes\n                // at a time.\n                mstore(mc, mload(cc))\n            }\n\n            // Add the length of _postBytes to the current length of tempBytes\n            // and store it as the new length in the first 32 bytes of the\n            // tempBytes memory.\n            length := mload(_postBytes)\n            mstore(tempBytes, add(length, mload(tempBytes)))\n\n            // Move the memory counter back from a multiple of 0x20 to the\n            // actual end of the _preBytes data.\n            mc := end\n            // Stop copying when the memory counter reaches the new combined\n            // length of the arrays.\n            end := add(mc, length)\n\n            for {\n                let cc := add(_postBytes, 0x20)\n            } lt(mc, end) {\n                mc := add(mc, 0x20)\n                cc := add(cc, 0x20)\n            } {\n                mstore(mc, mload(cc))\n            }\n\n            // Update the free-memory pointer by padding our last write location\n            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n            // next 32 byte block, then round down to the nearest multiple of\n            // 32. If the sum of the length of the two arrays is zero then add\n            // one before rounding down to leave a blank 32 bytes (the length block with 0).\n            mstore(0x40, and(\n              add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n              not(31) // Round down to the nearest 32 bytes.\n            ))\n        }\n\n        return tempBytes;\n    }\n\n    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n        assembly {\n            // Read the first 32 bytes of _preBytes storage, which is the length\n            // of the array. (We don't need to use the offset into the slot\n            // because arrays use the entire slot.)\n            let fslot := sload(_preBytes.slot)\n            // Arrays of 31 bytes or less have an even value in their slot,\n            // while longer arrays have an odd value. The actual length is\n            // the slot divided by two for odd values, and the lowest order\n            // byte divided by two for even values.\n            // If the slot is even, bitwise and the slot with 255 and divide by\n            // two to get the length. If the slot is odd, bitwise and the slot\n            // with -1 and divide by two.\n            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n            let mlength := mload(_postBytes)\n            let newlength := add(slength, mlength)\n            // slength can contain both the length and contents of the array\n            // if length < 32 bytes so let's prepare for that\n            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n            switch add(lt(slength, 32), lt(newlength, 32))\n            case 2 {\n                // Since the new array still fits in the slot, we just need to\n                // update the contents of the slot.\n                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n                sstore(\n                    _preBytes.slot,\n                    // all the modifications to the slot are inside this\n                    // next block\n                    add(\n                        // we can just add to the slot contents because the\n                        // bytes we want to change are the LSBs\n                        fslot,\n                        add(\n                            mul(\n                                div(\n                                    // load the bytes from memory\n                                    mload(add(_postBytes, 0x20)),\n                                    // zero all bytes to the right\n                                    exp(0x100, sub(32, mlength))\n                                ),\n                                // and now shift left the number of bytes to\n                                // leave space for the length in the slot\n                                exp(0x100, sub(32, newlength))\n                            ),\n                            // increase length by the double of the memory\n                            // bytes length\n                            mul(mlength, 2)\n                        )\n                    )\n                )\n            }\n            case 1 {\n                // The stored value fits in the slot, but the combined value\n                // will exceed it.\n                // get the keccak hash to get the contents of the array\n                mstore(0x0, _preBytes.slot)\n                let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n                // save new length\n                sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n                // The contents of the _postBytes array start 32 bytes into\n                // the structure. Our first read should obtain the `submod`\n                // bytes that can fit into the unused space in the last word\n                // of the stored array. To get this, we read 32 bytes starting\n                // from `submod`, so the data we read overlaps with the array\n                // contents by `submod` bytes. Masking the lowest-order\n                // `submod` bytes allows us to add that value directly to the\n                // stored value.\n\n                let submod := sub(32, slength)\n                let mc := add(_postBytes, submod)\n                let end := add(_postBytes, mlength)\n                let mask := sub(exp(0x100, submod), 1)\n\n                sstore(\n                    sc,\n                    add(\n                        and(\n                            fslot,\n                            0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00\n                        ),\n                        and(mload(mc), mask)\n                    )\n                )\n\n                for {\n                    mc := add(mc, 0x20)\n                    sc := add(sc, 1)\n                } lt(mc, end) {\n                    sc := add(sc, 1)\n                    mc := add(mc, 0x20)\n                } {\n                    sstore(sc, mload(mc))\n                }\n\n                mask := exp(0x100, sub(mc, end))\n\n                sstore(sc, mul(div(mload(mc), mask), mask))\n            }\n            default {\n                // get the keccak hash to get the contents of the array\n                mstore(0x0, _preBytes.slot)\n                // Start copying to the last used word of the stored array.\n                let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n                // save new length\n                sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n                // Copy over the first `submod` bytes of the new data as in\n                // case 1 above.\n                let slengthmod := mod(slength, 32)\n                let mlengthmod := mod(mlength, 32)\n                let submod := sub(32, slengthmod)\n                let mc := add(_postBytes, submod)\n                let end := add(_postBytes, mlength)\n                let mask := sub(exp(0x100, submod), 1)\n\n                sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n                for {\n                    sc := add(sc, 1)\n                    mc := add(mc, 0x20)\n                } lt(mc, end) {\n                    sc := add(sc, 1)\n                    mc := add(mc, 0x20)\n                } {\n                    sstore(sc, mload(mc))\n                }\n\n                mask := exp(0x100, sub(mc, end))\n\n                sstore(sc, mul(div(mload(mc), mask), mask))\n            }\n        }\n    }\n\n    function slice(\n        bytes memory _bytes,\n        uint256 _start,\n        uint256 _length\n    )\n        internal\n        pure\n        returns (bytes memory)\n    {\n        require(_length + 31 >= _length, \"slice_overflow\");\n        require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n        bytes memory tempBytes;\n\n        assembly {\n            switch iszero(_length)\n            case 0 {\n                // Get a location of some free memory and store it in tempBytes as\n                // Solidity does for memory variables.\n                tempBytes := mload(0x40)\n\n                // The first word of the slice result is potentially a partial\n                // word read from the original array. To read it, we calculate\n                // the length of that partial word and start copying that many\n                // bytes into the array. The first word we copy will start with\n                // data we don't care about, but the last `lengthmod` bytes will\n                // land at the beginning of the contents of the new array. When\n                // we're done copying, we overwrite the full first word with\n                // the actual length of the slice.\n                let lengthmod := and(_length, 31)\n\n                // The multiplication in the next line is necessary\n                // because when slicing multiples of 32 bytes (lengthmod == 0)\n                // the following copy loop was copying the origin's length\n                // and then ending prematurely not copying everything it should.\n                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n                let end := add(mc, _length)\n\n                for {\n                    // The multiplication in the next line has the same exact purpose\n                    // as the one above.\n                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n                } lt(mc, end) {\n                    mc := add(mc, 0x20)\n                    cc := add(cc, 0x20)\n                } {\n                    mstore(mc, mload(cc))\n                }\n\n                mstore(tempBytes, _length)\n\n                //update free-memory pointer\n                //allocating the array padded to 32 bytes like the compiler does now\n                mstore(0x40, and(add(mc, 31), not(31)))\n            }\n            //if we want a zero-length slice let's just return a zero-length array\n            default {\n                tempBytes := mload(0x40)\n                //zero out the 32 bytes slice we are about to return\n                //we need to do it because Solidity does not garbage collect\n                mstore(tempBytes, 0)\n\n                mstore(0x40, add(tempBytes, 0x20))\n            }\n        }\n\n        return tempBytes;\n    }\n\n    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {\n        require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n        address tempAddress;\n\n        assembly {\n            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n        }\n\n        return tempAddress;\n    }\n\n    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {\n        require(_bytes.length >= _start + 1 , \"toUint8_outOfBounds\");\n        uint8 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x1), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {\n        require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n        uint16 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x2), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {\n        require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n        uint32 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x4), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {\n        require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n        uint64 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x8), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {\n        require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n        uint96 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0xc), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {\n        require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n        uint128 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x10), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {\n        require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n        uint256 tempUint;\n\n        assembly {\n            tempUint := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempUint;\n    }\n\n    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {\n        require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n        bytes32 tempBytes32;\n\n        assembly {\n            tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n        }\n\n        return tempBytes32;\n    }\n\n    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n        bool success = true;\n\n        assembly {\n            let length := mload(_preBytes)\n\n            // if lengths don't match the arrays are not equal\n            switch eq(length, mload(_postBytes))\n            case 1 {\n                // cb is a circuit breaker in the for loop since there's\n                //  no said feature for inline assembly loops\n                // cb = 1 - don't breaker\n                // cb = 0 - break\n                let cb := 1\n\n                let mc := add(_preBytes, 0x20)\n                let end := add(mc, length)\n\n                for {\n                    let cc := add(_postBytes, 0x20)\n                // the next line is the loop condition:\n                // while(uint256(mc < end) + cb == 2)\n                } eq(add(lt(mc, end), cb), 2) {\n                    mc := add(mc, 0x20)\n                    cc := add(cc, 0x20)\n                } {\n                    // if any of these checks fails then arrays are not equal\n                    if iszero(eq(mload(mc), mload(cc))) {\n                        // unsuccess:\n                        success := 0\n                        cb := 0\n                    }\n                }\n            }\n            default {\n                // unsuccess:\n                success := 0\n            }\n        }\n\n        return success;\n    }\n\n    function equal_nonAligned(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n        bool success = true;\n\n        assembly {\n            let length := mload(_preBytes)\n\n            // if lengths don't match the arrays are not equal\n            switch eq(length, mload(_postBytes))\n            case 1 {\n                // cb is a circuit breaker in the for loop since there's\n                //  no said feature for inline assembly loops\n                // cb = 1 - don't breaker\n                // cb = 0 - break\n                let cb := 1\n\n                let endMinusWord := add(_preBytes, length)\n                let mc := add(_preBytes, 0x20)\n                let cc := add(_postBytes, 0x20)\n\n                for {\n                // the next line is the loop condition:\n                // while(uint256(mc < endWord) + cb == 2)\n                } eq(add(lt(mc, endMinusWord), cb), 2) {\n                    mc := add(mc, 0x20)\n                    cc := add(cc, 0x20)\n                } {\n                    // if any of these checks fails then arrays are not equal\n                    if iszero(eq(mload(mc), mload(cc))) {\n                        // unsuccess:\n                        success := 0\n                        cb := 0\n                    }\n                }\n\n                // Only if still successful\n                // For <1 word tail bytes\n                if gt(success, 0) {\n                    // Get the remainder of length/32\n                    // length % 32 = AND(length, 32 - 1)\n                    let numTailBytes := and(length, 0x1f)\n                    let mcRem := mload(mc)\n                    let ccRem := mload(cc)\n                    for {\n                        let i := 0\n                    // the next line is the loop condition:\n                    // while(uint256(i < numTailBytes) + cb == 2)\n                    } eq(add(lt(i, numTailBytes), cb), 2) {\n                        i := add(i, 1)\n                    } {\n                        if iszero(eq(byte(i, mcRem), byte(i, ccRem))) {\n                            // unsuccess:\n                            success := 0\n                            cb := 0\n                        }\n                    }\n                }\n            }\n            default {\n                // unsuccess:\n                success := 0\n            }\n        }\n\n        return success;\n    }\n\n    function equalStorage(\n        bytes storage _preBytes,\n        bytes memory _postBytes\n    )\n        internal\n        view\n        returns (bool)\n    {\n        bool success = true;\n\n        assembly {\n            // we know _preBytes_offset is 0\n            let fslot := sload(_preBytes.slot)\n            // Decode the length of the stored array like in concatStorage().\n            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n            let mlength := mload(_postBytes)\n\n            // if lengths don't match the arrays are not equal\n            switch eq(slength, mlength)\n            case 1 {\n                // slength can contain both the length and contents of the array\n                // if length < 32 bytes so let's prepare for that\n                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n                if iszero(iszero(slength)) {\n                    switch lt(slength, 32)\n                    case 1 {\n                        // blank the last byte which is the length\n                        fslot := mul(div(fslot, 0x100), 0x100)\n\n                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n                            // unsuccess:\n                            success := 0\n                        }\n                    }\n                    default {\n                        // cb is a circuit breaker in the for loop since there's\n                        //  no said feature for inline assembly loops\n                        // cb = 1 - don't breaker\n                        // cb = 0 - break\n                        let cb := 1\n\n                        // get the keccak hash to get the contents of the array\n                        mstore(0x0, _preBytes.slot)\n                        let sc := keccak256(0x0, 0x20)\n\n                        let mc := add(_postBytes, 0x20)\n                        let end := add(mc, mlength)\n\n                        // the next line is the loop condition:\n                        // while(uint256(mc < end) + cb == 2)\n                        for {} eq(add(lt(mc, end), cb), 2) {\n                            sc := add(sc, 1)\n                            mc := add(mc, 0x20)\n                        } {\n                            if iszero(eq(sload(sc), mload(mc))) {\n                                // unsuccess:\n                                success := 0\n                                cb := 0\n                            }\n                        }\n                    }\n                }\n            }\n            default {\n                // unsuccess:\n                success := 0\n            }\n        }\n\n        return success;\n    }\n}\n"},{"file_path":"contracts-0.8/common/interfaces/IScoreReader.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.8.7 <0.8.20;\n\ninterface IScoreReader {\n  function getValidatorScore(address validator) external view returns (uint256);\n  function getGroupScore(address validator) external view returns (uint256);\n}\n"},{"file_path":"contracts/common/interfaces/IAccounts.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface IAccounts {\n  function setAccountDataEncryptionKey(bytes calldata) external;\n  function setMetadataURL(string calldata) external;\n  function setName(string calldata) external;\n  function setWalletAddress(address, uint8, bytes32, bytes32) external;\n  function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external;\n\n  function authorizeVoteSigner(address, uint8, bytes32, bytes32) external;\n  function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external;\n  function authorizeValidatorSignerWithPublicKey(\n    address,\n    uint8,\n    bytes32,\n    bytes32,\n    bytes calldata\n  ) external;\n  function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external;\n  function setEip712DomainSeparator() external;\n  function createAccount() external returns (bool);\n\n  function setPaymentDelegation(address, uint256) external;\n\n  function isAccount(address) external view returns (bool);\n  function voteSignerToAccount(address) external view returns (address);\n  function validatorSignerToAccount(address) external view returns (address);\n  function attestationSignerToAccount(address) external view returns (address);\n  function signerToAccount(address) external view returns (address);\n  function getAttestationSigner(address) external view returns (address);\n  function getValidatorSigner(address) external view returns (address);\n  function getVoteSigner(address) external view returns (address);\n  function hasAuthorizedVoteSigner(address) external view returns (bool);\n  function hasAuthorizedValidatorSigner(address) external view returns (bool);\n  function hasAuthorizedAttestationSigner(address) external view returns (bool);\n\n  function batchGetMetadataURL(\n    address[] calldata\n  ) external view returns (uint256[] memory, bytes memory);\n\n  function getDataEncryptionKey(address) external view returns (bytes memory);\n  function getWalletAddress(address) external view returns (address);\n  function getMetadataURL(address) external view returns (string memory);\n\n  function getName(address) external view returns (string memory);\n\n  function getPaymentDelegation(address) external view returns (address, uint256);\n  function isSigner(address, address, bytes32) external view returns (bool);\n}\n"},{"file_path":"lib/openzeppelin-contracts8/contracts/utils/math/SafeMath.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)\n\npragma solidity ^0.8.0;\n\n// CAUTION\n// This version of SafeMath should only be used with Solidity 0.8 or later,\n// because it relies on the compiler's built in overflow checks.\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations.\n *\n * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler\n * now has built in overflow checking.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            uint256 c = a + b;\n            if (c < a) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b > a) return (false, 0);\n            return (true, a - b);\n        }\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n            // benefit is lost if 'b' is also tested.\n            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n            if (a == 0) return (true, 0);\n            uint256 c = a * b;\n            if (c / a != b) return (false, 0);\n            return (true, c);\n        }\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a / b);\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        unchecked {\n            if (b == 0) return (false, 0);\n            return (true, a % b);\n        }\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a * b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator.\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b <= a, errorMessage);\n            return a - b;\n        }\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a / b;\n        }\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        unchecked {\n            require(b > 0, errorMessage);\n            return a % b;\n        }\n    }\n}\n"},{"file_path":"contracts/common/Initializable.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\n/**\n * @title Used with proxied contracts that have an `initialize` function.\n * @notice Ensures the `initialize` function:\n *         - gets called only once\n *         - cannot be called on the logic contract.\n */\ncontract Initializable {\n  bool public initialized;\n\n  /**\n   * @notice Ensures the initializer function cannot be called more than once.\n   */\n  modifier initializer() {\n    require(!initialized, \"contract already initialized\");\n    initialized = true;\n    _;\n  }\n\n  /**\n   * @notice By default, ensures that the `initialize` function cannot be called\n   * on the logic contract.\n   * @param testingDeployment When set to true, allows the `initialize` function\n   * to be called, which is useful in testing when not setting up with a Proxy.\n   */\n  constructor(bool testingDeployment) public {\n    if (!testingDeployment) {\n      initialized = true;\n    }\n  }\n}\n"},{"file_path":"contracts/common/interfaces/ICeloUnreleasedTreasury.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ninterface ICeloUnreleasedTreasury {\n  /**\n   * @notice Releases the Celo to the specified address.\n   * @param to The address to release the amount to.\n   * @param amount The amount to release.\n   */\n  function release(address to, uint256 amount) external;\n\n  function getRemainingBalanceToRelease() external view returns (uint256);\n}\n"},{"file_path":"contracts-0.8/common/IsL2Check.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.8.20;\n\n/**\n * @title Based on predeploy returns whether this is L1 or L2.\n */\ncontract IsL2Check {\n  address constant proxyAdminAddress = 0x4200000000000000000000000000000000000018;\n\n  /**\n   * @notice Throws if called on L2.\n   */\n  modifier onlyL1() {\n    allowOnlyL1();\n    _;\n  }\n\n  /**\n   * @notice Throws if called on L1.\n   */\n  modifier onlyL2() {\n    if (!isL2()) {\n      revert(\"This method is not supported in L1.\");\n    }\n    _;\n  }\n\n  /**\n   * @notice Checks to see if current network is Celo L2.\n   * @return Whether or not the current network is a Celo L2.\n   */\n  function isL2() internal view returns (bool) {\n    uint32 size;\n    address _addr = proxyAdminAddress;\n    assembly {\n      size := extcodesize(_addr)\n    }\n    return (size > 0);\n  }\n\n  /**\n   * @notice Used to restrict usage of the parent function to L1 execution.\n   * @dev Reverts if called on a Celo L2 network.\n   */\n  function allowOnlyL1() internal view {\n    if (isL2()) {\n      revert(\"This method is no longer supported in L2.\");\n    }\n  }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"bool","name":"test","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"CommissionUpdateDelaySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"GroupLockedGoldRequirementsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"size","type":"uint256"}],"name":"MaxGroupSizeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxCommission","type":"uint256"}],"name":"MaxVoterRewardCommissionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"length","type":"uint256"}],"name":"MembershipHistoryLengthSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"registryAddress","type":"address"}],"name":"RegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":true,"internalType":"address","name":"group","type":"address"}],"name":"ValidatorAffiliated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":true,"internalType":"address","name":"group","type":"address"}],"name":"ValidatorDeaffiliated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorDeregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"},{"indexed":false,"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"}],"name":"ValidatorEcdsaPublicKeyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":false,"internalType":"uint256","name":"commission","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"activationBlock","type":"uint256"}],"name":"ValidatorGroupCommissionUpdateQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":false,"internalType":"uint256","name":"commission","type":"uint256"}],"name":"ValidatorGroupCommissionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"}],"name":"ValidatorGroupDeregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorGroupMemberAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorGroupMemberRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorGroupMemberReordered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":false,"internalType":"uint256","name":"commission","type":"uint256"}],"name":"ValidatorGroupRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":false,"internalType":"uint256","name":"commission","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"activationBlock","type":"uint256"}],"name":"ValidatorGroupVoterRewardCommissionUpdateQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"group","type":"address"},{"indexed":false,"internalType":"uint256","name":"commission","type":"uint256"}],"name":"ValidatorGroupVoterRewardCommissionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"ValidatorLockedGoldRequirementsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorRegistered","type":"event"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"address","name":"lesser","type":"address"},{"internalType":"address","name":"greater","type":"address"}],"name":"addFirstMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"addMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"group","type":"address"}],"name":"affiliate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"blsKey","type":"bytes"},{"internalType":"bytes","name":"blsPop","type":"bytes"}],"name":"checkProofOfPossession","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"commissionUpdateDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"score","type":"uint256"},{"internalType":"uint256","name":"maxPayment","type":"uint256"}],"name":"computeEpochReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deaffiliate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deprecated_downtimeGracePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"deregisterValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"deregisterValidatorGroup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validatorAccount","type":"address"}],"name":"forceDeaffiliateIfValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"aNumerator","type":"uint256"},{"internalType":"uint256","name":"aDenominator","type":"uint256"},{"internalType":"uint256","name":"bNumerator","type":"uint256"},{"internalType":"uint256","name":"bDenominator","type":"uint256"},{"internalType":"uint256","name":"exponent","type":"uint256"},{"internalType":"uint256","name":"_decimals","type":"uint256"}],"name":"fractionMulExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountLockedGoldRequirement","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"getBlockNumberFromHeader","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCommissionUpdateDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEpochNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getEpochNumberOfBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getEpochSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGroupLockedGoldRequirements","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getGroupNumMembers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"getGroupsNumMembers","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaxGroupSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getMembershipHistory","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMembershipHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getMembershipInLastEpoch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"getMembershipInLastEpochFromSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNumRegisteredValidators","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getParentSealBitmap","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegisteredValidatorGroups","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegisteredValidatorSigners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRegisteredValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"getTopGroupValidators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"n","type":"uint256"}],"name":"getTopGroupValidatorsAccounts","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getValidator","outputs":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"},{"internalType":"bytes","name":"blsPublicKey","type":"bytes"},{"internalType":"address","name":"affiliation","type":"address"},{"internalType":"uint256","name":"score","type":"uint256"},{"internalType":"address","name":"signer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getValidatorGroup","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getValidatorGroupSlashingMultiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getValidatorLockedGoldRequirements","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getValidatorsGroup","outputs":[{"internalType":"address","name":"group","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"getVerifiedSealBitmapFromHeader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVersionNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getVoterRewardCommission","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"groupLockedGoldRequirements","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"epochNumber","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"groupMembershipInEpoch","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"halveSlashingMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"header","type":"bytes"}],"name":"hashHeader","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"registryAddress","type":"address"},{"internalType":"uint256","name":"groupRequirementValue","type":"uint256"},{"internalType":"uint256","name":"groupRequirementDuration","type":"uint256"},{"internalType":"uint256","name":"validatorRequirementValue","type":"uint256"},{"internalType":"uint256","name":"validatorRequirementDuration","type":"uint256"},{"internalType":"uint256","name":"_membershipHistoryLength","type":"uint256"},{"internalType":"uint256","name":"_slashingMultiplierResetPeriod","type":"uint256"},{"internalType":"uint256","name":"_maxGroupSize","type":"uint256"},{"components":[{"internalType":"uint256","name":"commissionUpdateDelay","type":"uint256"}],"internalType":"struct Validators.InitParams","name":"initParams","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isValidatorGroup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGroupSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxVoterRewardCommission","outputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxVoterRewardCommissionLastReducedBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"meetsAccountLockedGoldRequirements","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"membershipHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"minQuorumSize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minQuorumSizeInCurrentSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintStableToEpochManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"numberValidatorsInCurrentSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"numberValidatorsInSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"}],"name":"registerValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"commission","type":"uint256"}],"name":"registerValidatorGroup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"}],"name":"registerValidatorNoBls","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract IRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"removeMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"address","name":"lesserMember","type":"address"},{"internalType":"address","name":"greaterMember","type":"address"}],"name":"reorderMember","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetSlashingMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"delay","type":"uint256"}],"name":"setCommissionUpdateDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setGroupLockedGoldRequirements","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"size","type":"uint256"}],"name":"setMaxGroupSize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxCommission","type":"uint256"}],"name":"setMaxVoterRewardCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"setMembershipHistoryLength","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"commission","type":"uint256"}],"name":"setNextCommissionUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"commission","type":"uint256"}],"name":"setNextVoterRewardCommissionUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"registryAddress","type":"address"}],"name":"setRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"setSlashingMultiplierResetPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setValidatorLockedGoldRequirements","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"slashingMultiplierResetPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"signer","type":"address"},{"internalType":"bytes","name":"ecdsaPublicKey","type":"bytes"}],"name":"updateEcdsaPublicKey","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateVoterRewardCommission","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"validatorAddressFromCurrentSet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorLockedGoldRequirements","outputs":[{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"duration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"validatorSignerAddressFromCurrentSet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"validatorSignerAddressFromSet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":null}