FRAX Price: $0.99 (+2.41%)

Contract

0xe1336De4a4d9f7cC9E0f58Af513Cd102B32e59C1

Overview

FRAX Balance | FXTL Balance

0.000000002928576287 FRAX | 210 FXTL

FRAX Value

Less Than $0.01 (@ $0.99/FRAX)

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

2 Internal Transactions and 2 Token Transfers found.

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
264691302025-10-06 11:09:31110 days ago1759748971
0xe1336De4...2B32e59C1
0 FRAX
264122862025-10-05 3:34:43111 days ago1759635283
0xe1336De4...2B32e59C1
0 FRAX

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
FraxStaker

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 100000 runs

Other Settings:
cancun EvmVersion
File 1 of 7 : FraxStaker.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// =========================== Frax Staker ============================
// ====================================================================

import { OwnedUpgradeable } from "../Flox/OwnedUpgradeable.sol";
import { FraxStakerStructs } from "./interfaces/FraxStakerStructs.sol";
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable-5/utils/ReentrancyGuardUpgradeable.sol";

/**
 * @title FraxStaker
 * @author Frax Finance
 * @notice A smart contract that allows users to stake FRAX.
 * @dev Delegating one's stake doesn't transfer the balance to the delegatee, so the full deposit can be retrieved by
 *  the staker.
 * @dev This smart contract supports single-hop fractional delegation. This means that a staker can delegate their stake,
 *  but the delegatee cannot further delegate the accumulated delegations. Fractional delegation means that a
 *  staker can delegate a part of their stake to multiple delegatees.
 * @dev If they want to delegate their stake, they can only do so when they don't have an active stake.
 * @dev When the user initiates the withdrawal, their balance should start reporting as 0 (or their delegation shoud be
 *  revoked). They can only withdraw their FRAX after the cooldown period passes.
 * @dev User can't have a stake for themselves as well as a delegated stake at the same time.
 * @dev We are able to freeze, unfreeze, slash, and blacklist users. Frozen stakers should have a balance of 0 and
 *  blacklisted stakers should be ejected and shouldn't be able to stake again.
 * @dev May be used for validators in the future.
 * @dev Frax Reviewer(s) / Contributor(s)
 *  Jan Turk: https://github.com/ThunderDeliverer
 *  Travis Moore: https://github.com/FortisFortuna
 *  Sam Kazemian: https://github.com/samkazemian
 *  Dennis Denett: https://github.com/denett
 *  Carter Carlson: https://github.com/pegahcarter
 */
contract FraxStaker is OwnedUpgradeable, FraxStakerStructs, ReentrancyGuardUpgradeable {
    /// @notice Address that is the recipient of slashed stakes.
    address public SLASHING_RECIPIENT;

    /**
     * @notice Used to track the blacklisted stakers.
     * @dev staker Address of the staker.
     * @dev isBlacklisted True if the address is blacklisted.
     */
    mapping(address staker => bool isBlacklisted) public blacklist;
    /**
     * @notice Used to keep track of the frozen stakers.
     * @dev address Address of the staker.
     * @dev isFrozen Whether the staker's stake is frozen or not.
     */
    mapping(address staker => bool isFrozen) public isFrozenStaker;
    /**
     * @notice Used to track the Frax contributors.
     * @dev contributor Address of the Frax contributor.
     * @dev isContributor True if the address is a Frax contributor.
     */
    mapping(address contributor => bool isContributor) public isFraxContributor;
    /**
     * @notice Used to track the Frax sentinels.
     * @dev Frax sentinels are addresses that can freeze, unfreeze, slash, and blacklist stakers.
     * @dev sentinel Address of the sentinel.
     * @dev isSentinel True if the address is a sentinel.
     */
    mapping(address sentinel => bool isSentinel) public isFraxSentinel;
    /**
     * @notice Used to track the stakes of each user.
     * @dev staker Address of the staker.
     * @dev stake Stake of the user.
     */
    mapping(address staker => Stake stake) public stakes;

    /// @notice The cooldown required before a staker can withdraw their stake.
    uint256 public withdrawalCooldown;

    /// @notice Version of this smart contract.
    string public version;

    /// @notice Variable to track if the contract is paused.
    bool public isPaused;

    /// @notice Used to make sure the contract is initialized only once.
    bool private _initialized;

    /// @dev reserve extra storage for future upgrades
    uint256[50] private __gap;

    /**
     * @notice The constructor disables the direct use of the implementation smart contract.
     */
    constructor() {
        __Owned_init(address(this));
        _initialized = true;
    }

    /**
     * @notice Used to initialize the smart contract.
     * @dev The initial owner is set as the deployer of the smart contract.
     * @dev The initial withdrawal cooldown is set for 90 days.
     * @dev The initial slashing recipient update delay is set for 7 days.
     * @param _owner Address of the owner of the smart contract
     * @param _version Version of this smart contract
     */
    function initialize(address _owner, string memory _version) public initializer {
        if (_initialized) revert AlreadyInitialized();

        _initialized = true;
        SLASHING_RECIPIENT = address(0xdead);
        version = _version;

        withdrawalCooldown = 90 days;

        __Owned_init(_owner);
        __ReentrancyGuard_init();
    }

    /**
     * @notice Returns the balance of the specified address.
     * @dev The balance is zero if the address is blacklisted, frozen, or has initiated a withdrawal.
     * @dev This is a sum of the staker's stake and the amount delegated to them, minus the amount they have delegated
     *  to others.
     * @dev Even if the user's balance is negated due to the user having initiated a withdrawal, the user can still
     *  receive the delegated balance.
     * @param account Address to check the balance of
     * @return The balance of the specified address
     */
    function balanceOf(address account) public view returns (uint256) {
        Stake memory stake = stakes[account];
        uint256 userBalance;

        if (blacklist[account] || isFrozenStaker[account]) {
            return 0;
        } else if (stake.initiatedWithdrawal) {
            userBalance = 0;
        } else {
            userBalance = stake.amountStaked - stake.amountDelegated;
        }

        return (userBalance + stake.amountDelegatedToStaker);
    }

    /**
     * @notice Returns the total supply of FRAX staked in the contract.
     * @return The total supply of FRAX staked in the contract
     */
    function totalSupply() public view returns (uint256) {
        return address(this).balance;
    }

    /**
     * @notice Stakes FRAX for the caller.
     * @dev Reverts if the contract is paused.
     * @dev Reverts if the caller's stake is frozen.
     * @dev Reverts if the caller is blacklisted.
     * @dev The amount of FRAX to stake is the value sent with the transaction.
     * @dev If the caller delegates their stake, this will increase the delegated stake instead of creating a separate
     *  stake for them.
     */
    function stakeFrax() public payable {
        _onlyWhenOperational();
        _onlyWhenNotFrozen(msg.sender);
        _onlyWhenNotBlacklisted(msg.sender);

        _stake(msg.value, msg.sender);

        Stake memory stake = stakes[msg.sender];
        if (stake.delegatee != address(0)) {
            _onlyWhenNotFrozen(stake.delegatee);
            _onlyWhenNotBlacklisted(stake.delegatee);

            _delegate(msg.sender, stake.delegatee, msg.value);
        }
    }

    /**
     * @notice Used to donate your FRAX to the recipient's stake.
     * @dev Reverts if the contract is paused.
     * @dev Reverts if the recipient is frozen or blacklisted.
     * @dev Reverts if there is no FRAX sent with the transaction.
     * @dev Reverts if the recipient has initiated a withdrawal.
     * @dev This can only be executed when the recipient has an active stake. This constraint is to ensure that the
     *  recipient can delegate their stake if they want to do so and that the ability to delegate is not disabled for
     *  the user that received the donation.
     * @param recipient Address of the recipient to donate the stake to
     */
    function donateStake(address recipient) external payable {
        _onlyWhenOperational();
        _onlyWhenNotFrozen(recipient);
        _onlyWhenNotBlacklisted(recipient);

        if (msg.value == 0) revert InvalidStakeAmount();

        Stake storage recipientStake = stakes[recipient];
        if (recipientStake.initiatedWithdrawal) revert WithdrawalInitiated();
        if (recipientStake.amountStaked == 0) revert InvalidStakeAmount();

        _stake(msg.value, recipient);

        if (recipientStake.delegatee != address(0)) {
            _onlyWhenNotFrozen(recipientStake.delegatee);
            _onlyWhenNotBlacklisted(recipientStake.delegatee);

            _delegate(recipient, recipientStake.delegatee, msg.value);
        }

        emit StakeDonation(msg.sender, recipient, msg.value);
    }

    /**
     * @notice Stakes the caller's FRAX, then delegates to someone else (delegatee). Note they are not adding to the
     *  delegatee's own position, if any.
     * @dev Reverts if the contract is paused.
     * @dev Reverts if the staker's stake is frozen.
     * @dev Reverts if the delegatee's stake is frozen.
     * @dev Reverts if the staker is blacklisted.
     * @dev Reverts if the delegatee is blacklisted.
     * @dev The amount of FRAX to stake is the value sent with the transaction.
     * @dev This overloaded function allows the staker to delegate their stake to another staker.
     * @dev If another delegation exists for the staker, this function will revert. They should remove that delegation first
     * @param _delegatee Address of the delegatee
     */
    function stakeFrax(address _delegatee) external payable {
        _onlyWhenOperational();
        _onlyWhenNotFrozen(msg.sender);
        _onlyWhenNotFrozen(_delegatee);
        _onlyWhenNotBlacklisted(msg.sender);
        _onlyWhenNotBlacklisted(_delegatee);

        // Make sure that the staker doesn't have a non-delegated stake
        if (stakes[msg.sender].amountStaked != stakes[msg.sender].amountDelegated) {
            revert NonDelegatedStakeAlreadyExists();
        }

        _stake(msg.value, msg.sender);
        _delegate(msg.sender, _delegatee, msg.value);
    }

    /**
     * @notice Initiates the withdrawal of the caller's stake.
     * @dev Reverts if the contract is paused.
     * @dev Reverts if the caller's stake is frozen.
     * @dev Reverts if the caller is blacklisted.
     */
    function initiateWithdrawal() external {
        _onlyWhenOperational();
        _onlyWhenNotFrozen(msg.sender);
        _onlyWhenNotBlacklisted(msg.sender);

        _revokeDelegation(msg.sender);
        _initiateWithdrawal(msg.sender);
    }

    /**
     * @notice Withdraws the staker's stake.
     * @dev Reverts if the contract is paused.
     * @dev Reverts if the staker's stake is frozen.
     * @dev This operation will revoke all delegations of the staker's stake. This is only done in this stepto ensure
     *  the delegations can't be instantly revoked.
     * @dev Blacklisted stakers can withdraw their remaining stake.
     */
    function withdrawStake() external nonReentrant {
        _onlyWhenOperational();
        _onlyWhenNotFrozen(msg.sender);

        _withdrawStake(msg.sender);
    }

    /**
     * @notice Allows a Frax contributor to force the withdrawal of staker's stake.
     * @dev This can only be called by a Frax contributor and is used to exit stakes that have passed the withdrawal
     *  cooldown period.
     * @dev Reverts if the staker's stake is frozen.
     * @dev This revokes the full amount of the delegated stake.
     * @param _staker Address of the staker to force withdraw
     */
    function forceStakeWithdrawal(address _staker) external nonReentrant {
        _onlyFraxContributor();
        _onlyWhenNotFrozen(_staker);

        _withdrawStake(_staker);
    }

    /**
     * @notice Adds a Frax contributor.
     * @dev Can only be called by the owner.
     * @param _contributor The address of the Frax contributor to add
     */
    function addFraxContributor(address _contributor) external {
        _onlyOwner();
        if (isFraxContributor[_contributor]) revert AlreadyFraxContributor();
        isFraxContributor[_contributor] = true;
        emit FraxContributorAdded(_contributor);
    }

    /**
     * @notice Removes a Frax contributor.
     * @dev Can only be called by the owner.
     * @param _contributor The address of the Frax contributor to remove
     */
    function removeFraxContributor(address _contributor) external {
        _onlyOwner();
        if (!isFraxContributor[_contributor]) revert NotFraxContributor();
        isFraxContributor[_contributor] = false;
        emit FraxContributorRemoved(_contributor);
    }

    /**
     * @notice Adds a Frax sentinel.
     * @dev Can only be called by the owner.
     * @param _sentinel The address of the Frax sentinel to add
     */
    function addFraxSentinel(address _sentinel) external {
        _onlyOwner();
        if (isFraxSentinel[_sentinel]) revert AlreadyFraxSentinel();
        isFraxSentinel[_sentinel] = true;
        emit FraxSentinelAdded(_sentinel);
    }

    /**
     * @notice Removes a Frax sentinel.
     * @dev Can only be called by the owner.
     * @param _sentinel The address of the Frax sentinel to remove
     */
    function removeFraxSentinel(address _sentinel) external {
        _onlyOwner();
        if (!isFraxSentinel[_sentinel]) revert NotFraxSentinel();
        isFraxSentinel[_sentinel] = false;
        emit FraxSentinelRemoved(_sentinel);
    }

    /**
     * @notice Updates the withdrawal cooldown duration.
     * @dev Can only be called by the owner.
     * @param _withdrawalCooldown The new withdrawal cooldown
     */
    function updateWithdrawalCooldown(uint256 _withdrawalCooldown) external {
        _onlyOwner();
        uint256 oldWithdrawalCooldown = withdrawalCooldown;
        withdrawalCooldown = _withdrawalCooldown;
        emit WithdrawalCooldownUpdated(oldWithdrawalCooldown, withdrawalCooldown);
    }

    /**
     * @notice Stops the operation of the smart contract.
     * @dev Can only be called by a Frax contributor.
     * @dev Can only be called if the contract is operational.
     */
    function stopOperation() external {
        _onlyFraxContributor();
        if (isPaused) revert ContractPaused();
        isPaused = true;
        emit OperationPaused(isPaused, block.timestamp);
    }

    /**
     * @notice Enables the operation of the smart contract.
     * @dev Can only be called by the owner.
     * @dev Can only be called if the contract is paused.
     */
    function restartOperation() external {
        _onlyOwner();
        if (!isPaused) revert ContractOperational();
        isPaused = false;
        emit OperationPaused(isPaused, block.timestamp);
    }

    /**
     * @notice Updates the slashing recipient address.
     * @dev Can only be called by the owner.
     * @dev The new slashing recipient cannot be the same as the old one.
     * @dev If the same address is passed, the operation will revert. This is to prevent passing a similar spoofed
     *  address to the function.
     * @param _slashingRecipient Address of the new slashing recipient
     */
    function updateSlashingRecipient(address _slashingRecipient) external {
        _onlyOwner();

        address currentSlashingRecipient = SLASHING_RECIPIENT;
        if (currentSlashingRecipient == _slashingRecipient) revert AlreadySlashingRecipient();

        SLASHING_RECIPIENT = _slashingRecipient;

        emit SlashingRecipientUpdated(currentSlashingRecipient, _slashingRecipient);
    }

    /**
     * @notice Slashes the staker's stake by the specified amount.
     * @dev Can only be called by the Frax sentinel.
     * @dev The user should be able to be slashed even if their stake is frozen.
     * @param _staker The address of the slashing recipient
     * @param _amount The amount of FRAX to slash
     */
    function slashStaker(address _staker, uint256 _amount) external nonReentrant {
        _onlyFraxSentinel();

        _slash(_staker, _amount);
    }

    /**
     * @notice Freezes the staker's stake.
     * @dev Can only be called by the Frax sentinel.
     * @dev The freezing operation will be reverted if the contract is paused.
     * @param _staker The address of the staker to freeze
     */
    function freezeStaker(address _staker) external {
        _onlyFraxSentinel();

        _freezeStaker(_staker);
    }

    /**
     * @notice Unfreezes the staker's stake.
     * @dev Can only be called by the Frax sentinel.
     * @dev The unfreezing operation will be reverted if the contract is paused.
     * @param _staker The address of the staker to unfreeze
     */
    function unfreezeStaker(address _staker) external {
        _onlyFraxSentinel();

        _unfreezeStaker(_staker);
    }

    /**
     * @notice Blacklists the staker.
     * @dev Can only be called by the Frax sentinel.
     * @param _staker The address of the staker to blacklist
     */
    function blacklistStaker(address _staker) external {
        _onlyFraxSentinel();

        _blacklistStaker(_staker);
    }

    /**
     * @notice Checks if an address is a Frax contributor.
     * @dev Reverts if the caller is not a Frax contributor.
     */
    function _onlyFraxContributor() internal view {
        if (!isFraxContributor[msg.sender]) revert NotFraxContributor();
    }

    /**
     * @notice Checks if an address is a Frax sentinel.
     * @dev Reverts if the caller is not a Frax sentinel.
     */
    function _onlyFraxSentinel() internal view {
        if (!isFraxSentinel[msg.sender]) revert NotFraxSentinel();
    }

    /**
     * @notice Checks if the contract is operational.
     * @dev Reverts if the contract is paused.
     */
    function _onlyWhenOperational() internal view {
        if (isPaused) revert ContractPaused();
    }

    /**
     * @notice Checks if the staker's stake is frozen.
     * @dev Reverts if the staker's stake is frozen.
     * @param _staker Address of the staker to check
     */
    function _onlyWhenNotFrozen(address _staker) internal view {
        if (isFrozenStaker[_staker]) revert FrozenStaker();
    }

    /**
     * @notice Checks if the staker is blacklisted.
     * @dev Reverts if the staker is blacklisted.
     * @param _staker Address of the staker to check
     */
    function _onlyWhenNotBlacklisted(address _staker) internal view {
        if (blacklist[_staker]) revert BlacklistedStaker();
    }

    /**
     * @notice Stakes FRAX for the caller.
     * @dev Since the amount to stake is the message value, we don't need to validate the user's balance.
     * @dev Attempting to stake zero FRAX will result in reverted execution.
     * @param _amount Amount of FRAX to stake
     * @param _staker Address of the staker
     */
    function _stake(uint256 _amount, address _staker) internal {
        if (_amount == 0) revert InvalidStakeAmount();

        Stake storage stake = stakes[_staker];
        if (stake.initiatedWithdrawal) revert WithdrawalInitiated();
        uint256 initialStake = stake.amountStaked;
        stake.amountStaked += _amount;

        emit StakeUpdated(_staker, initialStake, stake.amountStaked);
    }

    /**
     * @notice Initiates the withdrawal of the staker's stake.
     * @dev Reverts if the staker has no stake.
     * @dev Reverts if the staker has already initiated a withdrawal.
     * @param _staker Address of the staker
     */
    function _initiateWithdrawal(address _staker) internal {
        Stake storage stake = stakes[_staker];

        if (stake.amountStaked == 0) revert InvalidStakeAmount();
        if (stake.initiatedWithdrawal) revert WithdrawalInitiated();

        stake.initiatedWithdrawal = true;
        stake.unlockTime = block.timestamp + withdrawalCooldown;

        emit StakeWithdrawalInitiated(_staker, stake.amountStaked, stake.unlockTime);
    }

    /**
     * @notice Withdraws the staker's stake.
     * @dev Reverts if the staker has not initiated a withdrawal.
     * @dev Reverts if the staker's stake is not available to be withdrawn yet.
     * @param _staker Address of the staker
     */
    function _withdrawStake(address _staker) internal {
        Stake storage stake = stakes[_staker];

        if (!stake.initiatedWithdrawal) revert WithdrawalNotInitiated();
        if (block.timestamp < stake.unlockTime) revert WithdrawalNotAvailable();

        uint256 amount = stake.amountStaked;
        stake.amountStaked = 0;
        stake.initiatedWithdrawal = false;
        stake.unlockTime = 0;

        (bool success, ) = _staker.call{ value: amount }("");
        if (!success) revert TransferFailed();

        emit StakeUpdated(_staker, amount, 0);
    }

    /**
     * @notice Delegates a part of the staker's stake to another staker.
     * @dev Reverts if the staker wants to delegate more FRAX than available.
     * @dev Reverts if the staker has already delegated to amother delegatee.
     * @param _staker Address of the staker
     * @param _delegatee Address of the delegatee
     * @param _amount Amount of FRAX to delegate
     */
    function _delegate(address _staker, address _delegatee, uint256 _amount) internal {
        if (_staker == _delegatee) revert CannotDelegateToSelf();
        if (_delegatee == address(0)) revert InvalidDelegatee();

        Stake storage stakerStake = stakes[_staker];

        if (_amount > (stakerStake.amountStaked - stakerStake.amountDelegated)) revert InvalidStakeAmount();

        if (stakerStake.delegatee != address(0) && stakerStake.delegatee != _delegatee) {
            revert AlreadyDelegatedToAnotherDelegatee();
        }

        stakerStake.amountDelegated += _amount;
        stakerStake.delegatee = _delegatee;
        stakes[_delegatee].amountDelegatedToStaker += _amount;

        emit StakeDelegated(_staker, _delegatee, _amount);
    }

    /**
     * @notice Revokes staker's delegation.
     * @dev This revokes the full amount of the delegated stake.
     * @param _staker Address of the staker
     */
    function _revokeDelegation(address _staker) internal {
        Stake storage stake = stakes[_staker];

        address delegatee = stake.delegatee;

        uint256 amount = stake.amountDelegated;

        if (amount > 0) {
            stake.amountDelegated = 0;
            stakes[delegatee].amountDelegatedToStaker -= amount;

            stake.delegatee = address(0);

            emit StakeDelegationRevoked(_staker, delegatee, amount);
        }
    }

    /**
     * @notice Slashes the staker's stake.
     * @dev If the staker's stake is less than the amount to be slashed, the entire stake will be slashed.
     * @param _staker Address of the staker to slash
     * @param _amount The amount of FRAX to slash
     */
    function _slash(address _staker, uint256 _amount) internal {
        Stake storage stake = stakes[_staker];

        _amount = stake.amountStaked < _amount ? stake.amountStaked : _amount;

        stake.amountStaked -= _amount;

        if (stake.delegatee != address(0)) {
            // Only reduce the amount delegated to the staker if they are not frozen, otherwise the delegated stake is temporarily nullified already
            if (!isFrozenStaker[_staker]) {
                stakes[stake.delegatee].amountDelegatedToStaker -= _amount;
            }
            stake.amountDelegated -= _amount;
        }

        (bool success, ) = SLASHING_RECIPIENT.call{ value: _amount }("");
        if (!success) revert TransferFailed();

        emit Slashed(_staker, _amount);
    }

    /**
     * @notice Freezes the staker's stake.
     * @dev This is reversible and should be used when investigating a staker.
     * @dev Reverts if the staker's stake is already frozen.
     * @dev If the staker delegated their stake, freezing their stake will temporarily remove the delegated stake.
     * @param _staker Address of the staker to freeze
     */
    function _freezeStaker(address _staker) internal {
        if (isFrozenStaker[_staker]) revert AlreadyFrozenStaker();

        isFrozenStaker[_staker] = true;

        if (stakes[_staker].delegatee != address(0)) {
            stakes[stakes[_staker].delegatee].amountDelegatedToStaker -= stakes[_staker].amountStaked;
        }

        emit StakerFrozen(_staker, stakes[_staker].amountStaked);
    }

    /**
     * @notice Unfreezes the staker's stake.
     * @dev Reverts if the staker's stake is not frozen.
     * @param _staker Address of the staker to unfreeze
     */
    function _unfreezeStaker(address _staker) internal {
        if (!isFrozenStaker[_staker]) revert NotFrozenStaker();

        isFrozenStaker[_staker] = false;

        if (stakes[_staker].delegatee != address(0)) {
            stakes[stakes[_staker].delegatee].amountDelegatedToStaker += stakes[_staker].amountStaked;
        }

        emit StakerUnfrozen(_staker, stakes[_staker].amountStaked);
    }

    /**
     * @notice Blacklists the staker.
     * @dev This is irreversible and should be used when a staker is found to be malicious.
     * @dev If the staker should be slashed, slashing should be done before blacklisting.
     * @dev This forces the staker to withdraw their stake and prevents them from staking again.
     * @dev Reverts if the staker is already blacklisted.
     * @param _staker Address of the staker to blacklist
     */
    function _blacklistStaker(address _staker) internal {
        if (blacklist[_staker]) revert AlreadyBlacklistedStaker();

        if (isFrozenStaker[_staker]) {
            _unfreezeStaker(_staker);
        }

        blacklist[_staker] = true;

        if (stakes[_staker].amountStaked > 0) {
            _initiateWithdrawal(_staker);
        }
        _revokeDelegation(_staker);

        emit StakerBlacklisted(_staker, stakes[_staker].amountStaked);
    }

    /* ====================== EMERGENCIES AND FALLBACKS ====================== */
    /**
     * @notice Fallback function to receive FRAX and automatically stake sent funds for the sender.
     * @dev This simplifies recovery process of accidentally sent FRAX to the staking smart contract. It allows users to
     *  retrieve their accidentally sent FRAX by following the withdrawal process.
     */
    receive() external payable {
        stakeFrax();
    }

    /**
     * @notice Receives FRAX to increase the smart contract balance and does nothing else.
     */
    function donate() external payable {
        // Just accept FRAX and do nothing
    }

    /**
     * @notice Allows the owner to recover FRAX from the smart contract in case it somehow gets stuck.
     * @dev This function can only be called by the owner.
     * @dev The specified amount of FRAX will be transferred to the caller's (owner's) address.
     * @param _amount The amount of FRAX to recover
     */
    function recoverFrax(uint256 _amount) external nonReentrant {
        _onlyOwner();

        (bool success, ) = address(owner).call{ value: _amount }("");
        if (!success) revert TransferFailed();

        emit RecoveredFrax(_amount);
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ======================= OwnedUpgradeable ===========================
// ====================================================================

/**
 * @title OwnedUpgradeable
 * @author Frax Finance
 * @notice The OwnedUpgradeable contract has an owner address, and provides basic access control.
 */
contract OwnedUpgradeable {
    /// Emitted when attempting to initialize an already initialized contract.
    error OwnedAlreadyInitialized();
    /// Emitted when attempting to accept ownership when the caller is not the nominated owner.
    error InvalidOwnershipAcceptance();
    /// Emitted when the owner address is set to the zero address.
    error OwnerCannotBeZeroAddress();
    /// Emitted when the caller is not the owner.
    error OnlyOwner();

    /// Address of the owner of the smart contract.
    address public owner;
    /// Address of the nominated owner of the smart contract.
    address public nominatedOwner;
    /// Used to make sure the contract is initialized only once.
    bool private _initialized;

    /**
     * @notice Used to initialize the smart contract.
     * @param _owner The address of the owner
     */
    function __Owned_init(address _owner) public {
        if (_initialized) revert OwnedAlreadyInitialized();
        if (_owner == address(0)) revert OwnerCannotBeZeroAddress();

        _initialized = true;
        owner = _owner;

        emit OwnerChanged(address(0), _owner);
    }

    /**
     * @notice Allows the current owner to nominate a new owner.
     * @dev Reverts if the caller is not the current owner.
     * @dev Reverts if the nominated owner is the zero address.
     * @param _owner The address of the new owner
     */
    function nominateNewOwner(address _owner) external {
        _onlyOwner();

        if (_owner == address(0)) revert OwnerCannotBeZeroAddress();
        nominatedOwner = _owner;

        emit OwnerNominated(_owner);
    }

    /**
     * @notice Allows the current nominated owner to accept the ownership.
     * @dev Reverts if the caller is not the nominated owner.
     */
    function acceptOwnership() external {
        if (msg.sender != nominatedOwner) revert InvalidOwnershipAcceptance();

        address oldOwner = owner;
        owner = nominatedOwner;
        nominatedOwner = address(0);

        emit OwnerChanged(oldOwner, owner);
    }

    /**
     * @notice Restricts access to the function to the owner.
     * @dev Reverts if the caller is not the owner.
     */
    function _onlyOwner() internal view {
        if (msg.sender != owner) revert OnlyOwner();
    }

    /**
     * @notice Emitted when a new owner is nominated.
     * @param nominatedOwner The address of the nominated owner
     */
    event OwnerNominated(address indexed nominatedOwner);
    /**
     * @notice Emitted when the ownership is transferred.
     * @param previousOwner Address of the previous owner
     * @param newOwner Address of the new owner
     */
    event OwnerChanged(address indexed previousOwner, address indexed newOwner);
}

File 3 of 7 : FraxStakerStructs.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ======================= IFrax Staker Structs =======================
// ====================================================================

import { IFraxStakerErrors } from "./IFraxStakerErrors.sol";
import { IFraxStakerEvents } from "./IFraxStakerEvents.sol";

/**
 * @title IFraxStakerStructs
 * @author Frax Finance
 * @notice A collection of structs used by the FraxStaker system.
 */
contract FraxStakerStructs is IFraxStakerErrors, IFraxStakerEvents {
    /**
     * @notice A struct used to represent the stake of a user.
     * @dev The `unlockTime` is set to 0 if the stake is not slated for withdrawal.
     * @param amountStaked The amount of FRAX staked
     * @param amountDelegated The amount of FRAX delegated to other stakers
     * @param amountDelegatedToStaker The amount of FRAX delegated to this staker
     * @param unlockTime The time at which the stake can be withdrawn
     * @param delegatee The delegatee address of the staker
     * @param initiatedWithdrawal True if the stake withdrawal has been initiated
     * @param __gap Reserved 10 storage slots for future upgrades
     */
    struct Stake {
        uint256 amountStaked;
        uint256 amountDelegated;
        uint256 amountDelegatedToStaker;
        uint256 unlockTime;
        address delegatee;
        bool initiatedWithdrawal;
        uint256[10] __gap; // reserve extra storage for future upgrades
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    /// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
    struct ReentrancyGuardStorage {
        uint256 _status;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;

    function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
        assembly {
            $.slot := ReentrancyGuardStorageLocation
        }
    }

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if ($._status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        $._status = ENTERED;
    }

    function _nonReentrantAfter() private {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        $._status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
        return $._status == ENTERED;
    }
}

File 5 of 7 : IFraxStakerErrors.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;

// ====================================================================
// |     ______                   _______                             |
// |    / _____________ __  __   / ____(_____  ____ _____  ________   |
// |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
// |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
// | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
// |                                                                  |
// ====================================================================
// ==================== IFrax Staker Errors ========================
// ====================================================================

/**
 * @title IFraxStakerErrors
 * @author Frax Finance
 * @notice A collection of errors used by the FraxStaker system.
 */
interface IFraxStakerErrors {
    /// Emitted when the staker is already blacklisted.
    error AlreadyBlacklistedStaker();

    /// Emitted when attempting to delegate to someone when you already have an active delegation.
    error AlreadyDelegatedToAnotherDelegatee();

    /// Emitted when the owner tries to add a Frax contributor that is already a Frax contributor.
    error AlreadyFraxContributor();

    /// Emitted when the owner tries to add a Frax sentinel that is already a Frax sentinel.
    error AlreadyFraxSentinel();

    /// Emitted when the staker is aleady frozen.
    error AlreadyFrozenStaker();

    /// Emitted when the contract is already initialized.
    error AlreadyInitialized();

    /// Emitted when the supplied address is already the slashing recipient.
    error AlreadySlashingRecipient();

    /// Emitted when the staker is blacklisted.
    error BlacklistedStaker();

    /// Emitted when attempting to delegate to self.
    error CannotDelegateToSelf();

    /// Emitted when the contract is operational and the action that requires it to be paused is attempted.
    error ContractOperational();

    /// Emitted when the contract is paused and the action that requires it to be operational is attempted.
    error ContractPaused();

    /// Emitted when the staker is frozen and can't perform any actions.
    error FrozenStaker();

    /// Emitted when attempting to delegate to an address that is not a valid delegatee.
    error InvalidDelegatee();

    /// Emitted when attempting to create a stake with a zero amount.
    error InvalidStakeAmount();

    /// Emitted when the staker tries to delegate their stake when they already have an active non-delegated stake to someone else.
    error NonDelegatedStakeAlreadyExists();

    /// Emitted when the owner tries to remove a Frax contributor that is not a Frax contributor.
    error NotFraxContributor();

    /// Emitted when the owner tries to remove a Frax sentinel that is not a Frax sentinel.
    error NotFraxSentinel();

    /// Emitted when the staker is not frozen.
    error NotFrozenStaker();

    /// Emitted when the sender is not a flox contributor.
    error NotFloxContributor();

    /// Emitted when the FRAX transfer fails.
    error TransferFailed();

    /// Emitted when a user tries to deposit FRAX while they aleady have a stake with initiated withdrawal.
    /// They need to either cancel the withdrawal or wait for it to finish.
    error WithdrawalInitiated();

    /// Emitted when a user tries to withdraw their stake but it is not available to be withdrawn yet.
    error WithdrawalNotAvailable();

    /// Emitted when a user tries to withdraw their stake but the withdrawal has not been initiated yet.
    error WithdrawalNotInitiated();
}

File 6 of 7 : IFraxStakerEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/**
 * ====================================================================
 * |     ______                   _______                             |
 * |    / _____________ __  __   / ____(_____  ____ _____  ________   |
 * |   / /_  / ___/ __ `| |/_/  / /_  / / __ \/ __ `/ __ \/ ___/ _ \  |
 * |  / __/ / /  / /_/ _>  <   / __/ / / / / / /_/ / / / / /__/  __/  |
 * | /_/   /_/   \__,_/_/|_|  /_/   /_/_/ /_/\__,_/_/ /_/\___/\___/   |
 * |                                                                  |
 * ====================================================================
 * ===================== IFraxStakerEvents =========================
 * ====================================================================
 * Frax Finance: https://github.com/FraxFinance
 */

/**
 * @title IFraxStakerEvents
 * @author Frax Finance
 * @notice A collection of events used by the FraxStaker system.
 */
contract IFraxStakerEvents {
    /**
     * @notice Emitted when a contributor is added.
     * @param contributor The address of the contributor
     */
    event FraxContributorAdded(address indexed contributor);
    /**
     * @notice Emitted when a contributor is removed.
     * @param contributor The address of the contributor
     */
    event FraxContributorRemoved(address indexed contributor);
    /**
     * @notice Emitted when a sentinel is added.
     * @param sentinel The address of the sentinel
     */
    event FraxSentinelAdded(address indexed sentinel);
    /**
     * @notice Emitted when a sentinel is removed.
     * @param sentinel The address of the sentinel
     */
    event FraxSentinelRemoved(address indexed sentinel);
    /**
     * @notice Emitted when a new admin is proposed.
     * @param currentAdmin The address of the current admin
     * @param proposedFutureAdmin The address of the proposed future admin
     */
    event FutureAdminProposed(address indexed currentAdmin, address indexed proposedFutureAdmin);
    /**
     * @notice Emitted when a new admin is set.
     * @param oldAdmin The address of the old admin
     * @param newAdmin The address of the new admin
     */
    event NewAdmin(address indexed oldAdmin, address indexed newAdmin);
    /**
     * @notice Emitted when the contract is paused or unpaused.
     * @param paused True if the contract is paused, false if it is unpaused
     * @param timestamp The timestamp at which the pause or unpause occurred
     */
    event OperationPaused(bool paused, uint256 timestamp);
    /**
     * @notice Emitted when FRAX is recovered from the smart contract.
     * @param amount The amount of FRAX recovered
     */
    event RecoveredFrax(uint256 amount);
    /**
     * @notice Emitted when a stake is slashed.
     * @param staker The address of the staker
     * @param amount The amount of FRAX slashed
     */
    event Slashed(address indexed staker, uint256 amount);
    /**
     * @notice Emitted when the slashing recipient is updated.
     * @dev The slashing recipient is the address that receives the slashed FRAX.
     * @param oldSlashingRecipient Previous slashing recipient
     * @param newSlashingRecipient Updated slashing recipient
     */
    event SlashingRecipientUpdated(address indexed oldSlashingRecipient, address indexed newSlashingRecipient);
    /**
     * @notice Emitted when a stake is delegated.
     * @param staker Address of the staker
     * @param delegatee Address of the delegatee
     * @param amount Amount of FRAX delegated
     */
    event StakeDelegated(address indexed staker, address indexed delegatee, uint256 amount);
    /**
     * @notice Emitted when a stake delegation is revoked.
     * @dev The amount of FRAX in the event equals the amount of FRAX delegated to this specific delegatee by this
     *  staker.
     * @param staker Address of the staker
     * @param delegatee Address of the delegatee
     * @param amount Amount of FRAX delegation revoked
     */
    event StakeDelegationRevoked(address indexed staker, address indexed delegatee, uint256 amount);
    /**
     * @notice Emitted when an address donates FRAX to another staker's stake.
     * @param donor Address that donated FRAX to the recipient's stake
     * @param recipient Address that received the donated FRAX to their stake
     * @param amount Amount of FRAX that was donated
     */
    event StakeDonation(address indexed donor, address indexed recipient, uint256 amount);
    /**
     * @notice Emitted when a staker is blacklisted.
     * @param staker The address of the blacklisted staker
     * @param amount The amount of FRAX staked
     */
    event StakerBlacklisted(address indexed staker, uint256 amount);
    /**
     * @notice Emitted when a stake is frozen.
     * @param staker The address of the staker
     * @param amount The amount of FRAX staked
     */
    event StakerFrozen(address indexed staker, uint256 amount);
    /**
     * @notice Emitted when a stake is unfrozen.
     * @param staker The address of the staker
     * @param amount The amount of FRAX unfrozen
     */
    event StakerUnfrozen(address indexed staker, uint256 amount);
    /**
     * @notice Emitted when a stake is updated.
     * @param staker The address of the staker
     * @param initialStake The initial amount of FRAX staked
     * @param newStake The new amount of FRAX staked
     */
    event StakeUpdated(address indexed staker, uint256 initialStake, uint256 newStake);
    /**
     * @notice Emitted when a stake withdrawal is initiated.
     * @param staker The address of the staker
     * @param stake The amount of FRAX staked
     * @param withdrawalTimestamp The timestamp at which the withdrawal will be available
     */
    event StakeWithdrawalInitiated(address indexed staker, uint256 stake, uint256 withdrawalTimestamp);
    /**
     * @notice Emitted when the withdrawal cooldown period is updated.
     * @param oldCooldown Previous withdrawal cooldown period
     * @param newCooldown New withdrawal cooldown period
     */
    event WithdrawalCooldownUpdated(uint256 oldCooldown, uint256 newCooldown);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

Settings
{
  "remappings": [
    "frax-std/=lib/frax-standard-solidity/src/",
    "@fraxtal/=lib/fraxtal/packages/",
    "lib/fraxtal/packages/contracts-bedrock:src/=lib/fraxtal/packages/contracts-bedrock/src/",
    "lib/fraxtal/packages/contracts-bedrock:test/=lib/fraxtal/packages/contracts-bedrock/test/",
    "lib/fraxtal/packages/contracts-bedrock:scripts/=lib/fraxtal/packages/contracts-bedrock/scripts/",
    "lib/fraxtal/packages/contracts-bedrock:@cwia/=lib/fraxtal/packages/contracts-bedrock/lib/clones-with-immutable-args/src/",
    "lib/fraxtal/packages/contracts-bedrock:@openzeppelin/contracts-upgradeable/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/contracts/",
    "lib/fraxtal/packages/contracts-bedrock:@openzeppelin/contracts/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts/contracts/",
    "lib/fraxtal/packages/contracts-bedrock:@rari-capital/solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/",
    "lib/fraxtal/packages/contracts-bedrock:@lib-keccak/=lib/fraxtal/packages/contracts-bedrock/lib/lib-keccak/contracts/lib/",
    "lib/fraxtal/packages/contracts-bedrock:@solady/=lib/fraxtal/packages/contracts-bedrock/lib/solady/src/",
    "lib/fraxtal/packages/contracts-bedrock:solady/=lib/fraxtal/packages/contracts-bedrock/lib/solady/src/",
    "lib/fraxtal/packages/contracts-bedrock:@solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/src/",
    "lib/fraxtal/packages/contracts-bedrock:solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/src/",
    "lib/fraxtal/packages/contracts-bedrock:forge-std/=lib/fraxtal/packages/contracts-bedrock/lib/forge-std/src/",
    "lib/fraxtal/packages/contracts-bedrock:ds-test/=lib/fraxtal/packages/contracts-bedrock/lib/forge-std/lib/ds-test/src/",
    "lib/fraxtal/packages/contracts-bedrock:safe-contracts/=lib/fraxtal/packages/contracts-bedrock/lib/safe-contracts/contracts/",
    "lib/fraxtal/packages/contracts-bedrock:kontrol-cheatcodes/=lib/fraxtal/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
    "@eth-optimism/=lib/optimism/packages/",
    "lib/optimism/packages/contracts-bedrock:src/=lib/optimism/packages/contracts-bedrock/src/",
    "lib/optimism/packages/contracts-bedrock:test/=lib/optimism/packages/contracts-bedrock/test/",
    "lib/optimism/packages/contracts-bedrock:scripts/=lib/optimism/packages/contracts-bedrock/scripts/",
    "lib/optimism/packages/contracts-bedrock:@cwia/=lib/optimism/packages/contracts-bedrock/lib/clones-with-immutable-args/src/",
    "lib/optimism/packages/contracts-bedrock:@openzeppelin/contracts-upgradeable/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/contracts/",
    "lib/optimism/packages/contracts-bedrock:@openzeppelin/contracts/=lib/optimism/packages/contracts-bedrock/lib/openzeppelin-contracts/contracts/",
    "lib/optimism/packages/contracts-bedrock:@rari-capital/solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/",
    "lib/optimism/packages/contracts-bedrock:@lib-keccak/=lib/optimism/packages/contracts-bedrock/lib/lib-keccak/contracts/lib/",
    "lib/optimism/packages/contracts-bedrock:@solady/=lib/optimism/packages/contracts-bedrock/lib/solady/src/",
    "lib/optimism/packages/contracts-bedrock:solady/=lib/optimism/packages/contracts-bedrock/lib/solady/src/",
    "lib/optimism/packages/contracts-bedrock:@solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/",
    "lib/optimism/packages/contracts-bedrock:solmate/=lib/optimism/packages/contracts-bedrock/lib/solmate/src/",
    "lib/optimism/packages/contracts-bedrock:forge-std/=lib/optimism/packages/contracts-bedrock/lib/forge-std/src/",
    "lib/optimism/packages/contracts-bedrock:ds-test/=lib/optimism/packages/contracts-bedrock/lib/forge-std/lib/ds-test/src/",
    "lib/optimism/packages/contracts-bedrock:safe-contracts/=lib/optimism/packages/contracts-bedrock/lib/safe-contracts/contracts/",
    "lib/optimism/packages/contracts-bedrock:kontrol-cheatcodes/=lib/optimism/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
    "src/=src/",
    "@openzeppelin/contracts-upgradeable-5/=node_modules/@openzeppelin/contracts-upgradeable-5/",
    "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
    "@openzeppelin-4/=node_modules/@openzeppelin-4/",
    "@openzeppelin-5/=node_modules/@openzeppelin-5/",
    "@rari-capital/=node_modules/@rari-capital/",
    "automate/=lib/fraxtal/packages/contracts-bedrock/lib/automate/contracts/",
    "clones-with-immutable-args/=node_modules/clones-with-immutable-args/",
    "ds-test/=lib/frax-standard-solidity/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-v5/lib/erc4626-tests/",
    "forge-std/=lib/frax-standard-solidity/lib/forge-std/src/",
    "frax-standard-solidity/=lib/frax-standard-solidity/src/",
    "fraxtal/=lib/fraxtal/",
    "kontrol-cheatcodes/=lib/fraxtal/packages/contracts-bedrock/lib/kontrol-cheatcodes/src/",
    "lib-keccak/=lib/fraxtal/packages/contracts-bedrock/lib/lib-keccak/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts-v5/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts-v5/",
    "openzeppelin-contracts/=lib/fraxtal/packages/contracts-bedrock/lib/openzeppelin-contracts/",
    "optimism/=lib/optimism/",
    "prb-test/=lib/fraxtal/packages/contracts-bedrock/lib/automate/lib/prb-test/src/",
    "safe-contracts/=lib/fraxtal/packages/contracts-bedrock/lib/safe-contracts/contracts/",
    "solady-v0.0.245/=lib/fraxtal/packages/contracts-bedrock/lib/solady-v0.0.245/src/",
    "solady/=lib/fraxtal/packages/contracts-bedrock/lib/solady/",
    "solidity-bytes-utils/=lib/frax-standard-solidity/lib/solidity-bytes-utils/",
    "solmate/=lib/fraxtal/packages/contracts-bedrock/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyBlacklistedStaker","type":"error"},{"inputs":[],"name":"AlreadyDelegatedToAnotherDelegatee","type":"error"},{"inputs":[],"name":"AlreadyFraxContributor","type":"error"},{"inputs":[],"name":"AlreadyFraxSentinel","type":"error"},{"inputs":[],"name":"AlreadyFrozenStaker","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AlreadySlashingRecipient","type":"error"},{"inputs":[],"name":"BlacklistedStaker","type":"error"},{"inputs":[],"name":"CannotDelegateToSelf","type":"error"},{"inputs":[],"name":"ContractOperational","type":"error"},{"inputs":[],"name":"ContractPaused","type":"error"},{"inputs":[],"name":"FrozenStaker","type":"error"},{"inputs":[],"name":"InvalidDelegatee","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidOwnershipAcceptance","type":"error"},{"inputs":[],"name":"InvalidStakeAmount","type":"error"},{"inputs":[],"name":"NonDelegatedStakeAlreadyExists","type":"error"},{"inputs":[],"name":"NotFloxContributor","type":"error"},{"inputs":[],"name":"NotFraxContributor","type":"error"},{"inputs":[],"name":"NotFraxSentinel","type":"error"},{"inputs":[],"name":"NotFrozenStaker","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OwnedAlreadyInitialized","type":"error"},{"inputs":[],"name":"OwnerCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"WithdrawalInitiated","type":"error"},{"inputs":[],"name":"WithdrawalNotAvailable","type":"error"},{"inputs":[],"name":"WithdrawalNotInitiated","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"}],"name":"FraxContributorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"contributor","type":"address"}],"name":"FraxContributorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sentinel","type":"address"}],"name":"FraxSentinelAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sentinel","type":"address"}],"name":"FraxSentinelRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"currentAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"proposedFutureAdmin","type":"address"}],"name":"FutureAdminProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"OperationPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nominatedOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RecoveredFrax","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Slashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldSlashingRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newSlashingRecipient","type":"address"}],"name":"SlashingRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeDelegated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeDelegationRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"donor","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakeDonation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"initialStake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStake","type":"uint256"}],"name":"StakeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stake","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawalTimestamp","type":"uint256"}],"name":"StakeWithdrawalInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakerBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakerFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"StakerUnfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldCooldown","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCooldown","type":"uint256"}],"name":"WithdrawalCooldownUpdated","type":"event"},{"inputs":[],"name":"SLASHING_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"__Owned_init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contributor","type":"address"}],"name":"addFraxContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sentinel","type":"address"}],"name":"addFraxSentinel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"blacklist","outputs":[{"internalType":"bool","name":"isBlacklisted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"blacklistStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"donate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"donateStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"forceStakeWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"freezeStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"string","name":"_version","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initiateWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contributor","type":"address"}],"name":"isFraxContributor","outputs":[{"internalType":"bool","name":"isContributor","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sentinel","type":"address"}],"name":"isFraxSentinel","outputs":[{"internalType":"bool","name":"isSentinel","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"isFrozenStaker","outputs":[{"internalType":"bool","name":"isFrozen","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverFrax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contributor","type":"address"}],"name":"removeFraxContributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sentinel","type":"address"}],"name":"removeFraxSentinel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restartOperation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"slashStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakeFrax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegatee","type":"address"}],"name":"stakeFrax","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"stakes","outputs":[{"internalType":"uint256","name":"amountStaked","type":"uint256"},{"internalType":"uint256","name":"amountDelegated","type":"uint256"},{"internalType":"uint256","name":"amountDelegatedToStaker","type":"uint256"},{"internalType":"uint256","name":"unlockTime","type":"uint256"},{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"bool","name":"initiatedWithdrawal","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stopOperation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"unfreezeStaker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_slashingRecipient","type":"address"}],"name":"updateSlashingRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_withdrawalCooldown","type":"uint256"}],"name":"updateWithdrawalCooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalCooldown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6080604052348015600e575f80fd5b506016306029565b600a805461ff00191661010017905560d7565b600154600160a01b900460ff1615605357604051633965719d60e21b815260040160405180910390fd5b6001600160a01b038116607957604051630640d5fb60e51b815260040160405180910390fd5b6001805460ff60a01b1916600160a01b1790555f80546001600160a01b0383166001600160a01b0319909116811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a350565b612f8b806100e45f395ff3fe60806040526004361061025f575f3560e01c80639e1b9aa21161014b578063c76853de116100c6578063d8d9ec001161007c578063ed88c68e11610062578063ed88c68e1461026c578063f399e22e14610747578063f9f92be414610766575f80fd5b8063d8d9ec00146106fa578063e46a61b614610728575f80fd5b8063ce7cd5ad116100ac578063ce7cd5ad146106b2578063d6bd103f146106d1578063d6c89c60146106e5575f80fd5b8063c76853de14610674578063ca2a951214610693575f80fd5b8063b41a52581161011b578063b7a287ac11610101578063b7a287ac1461062d578063b81213851461064c578063bed9d86114610660575f80fd5b8063b41a5258146105fa578063b51d1d4f14610619575f80fd5b80639e1b9aa2146105755780639e48dc2b14610594578063b187bd26146105b3578063b234c544146105cc575f80fd5b806353a47bb7116101db57806386fc754c116101ab5780638da5cb5b116101915780638da5cb5b14610518578063989d1a87146105435780639c1f1f6314610562575f80fd5b806386fc754c146104f157806387c7655c146104f9575f80fd5b806353a47bb71461047157806354fd4d501461049d57806370a08231146104be57806379ba5097146104dd575f80fd5b806316934fc4116102305780631c29b8ba116102165780631c29b8ba146103e25780633b66042f146104015780634f99ef7514610452575f80fd5b806316934fc41461030657806318160ddd146103c6575f80fd5b806283b8d7146102725780630b376695146102855780630fbe82b8146102c85780631627540c146102e7575f80fd5b3661026e5761026c610794565b005b5f80fd5b61026c610280366004612b68565b6108c1565b348015610290575f80fd5b506102b361029f366004612b68565b60046020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156102d3575f80fd5b5061026c6102e2366004612b88565b610ab3565b3480156102f2575f80fd5b5061026c610301366004612b68565b610afa565b348015610311575f80fd5b50610381610320366004612b68565b60076020525f9081526040902080546001820154600283015460038401546004909401549293919290919073ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900460ff1686565b60408051968752602087019590955293850192909252606084015273ffffffffffffffffffffffffffffffffffffffff166080830152151560a082015260c0016102bf565b3480156103d1575f80fd5b50475b6040519081526020016102bf565b3480156103ed575f80fd5b5061026c6103fc366004612b68565b610bbd565b34801561040c575f80fd5b5060025461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102bf565b34801561045d575f80fd5b5061026c61046c366004612b68565b610c90565b34801561047c575f80fd5b5060015461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104a8575f80fd5b506104b1610cdb565b6040516102bf9190612bb0565b3480156104c9575f80fd5b506103d46104d8366004612b68565b610d67565b3480156104e8575f80fd5b5061026c610ece565b61026c610794565b348015610504575f80fd5b5061026c610513366004612c03565b610f9d565b348015610523575f80fd5b505f5461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561054e575f80fd5b5061026c61055d366004612b68565b610fea565b61026c610570366004612b68565b6110c7565b348015610580575f80fd5b5061026c61058f366004612b68565b611154565b34801561059f575f80fd5b5061026c6105ae366004612b68565b6112a5565b3480156105be575f80fd5b50600a546102b39060ff1681565b3480156105d7575f80fd5b506102b36105e6366004612b68565b60066020525f908152604090205460ff1681565b348015610605575f80fd5b5061026c610614366004612b68565b611382565b348015610624575f80fd5b5061026c61145b565b348015610638575f80fd5b5061026c610647366004612c03565b611489565b348015610657575f80fd5b5061026c61158d565b34801561066b575f80fd5b5061026c61163b565b34801561067f575f80fd5b5061026c61068e366004612b68565b611686565b34801561069e575f80fd5b5061026c6106ad366004612b68565b611697565b3480156106bd575f80fd5b5061026c6106cc366004612b68565b611770565b3480156106dc575f80fd5b5061026c611781565b3480156106f0575f80fd5b506103d460085481565b348015610705575f80fd5b506102b3610714366004612b68565b60056020525f908152604090205460ff1681565b348015610733575f80fd5b5061026c610742366004612b68565b611822565b348015610752575f80fd5b5061026c610761366004612c47565b611833565b348015610771575f80fd5b506102b3610780366004612b68565b60036020525f908152604090205460ff1681565b61079c611a68565b6107a533611aa5565b6107ae33611b04565b6107b83433611b63565b335f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015473ffffffffffffffffffffffffffffffffffffffff8116608085015274010000000000000000000000000000000000000000900460ff16151560a08401528151610140810192839052909160c0840191906005840190600a9082845b8154815260200190600101908083116108555750505091909252505050608081015190915073ffffffffffffffffffffffffffffffffffffffff16156108be576108a28160800151611aa5565b6108af8160800151611b04565b6108be33826080015134611c8a565b50565b6108c9611a68565b6108d281611aa5565b6108db81611b04565b345f03610914576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff161561098f576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f036109c9576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109d33483611b63565b600481015473ffffffffffffffffffffffffffffffffffffffff1615610a62576004810154610a179073ffffffffffffffffffffffffffffffffffffffff16611aa5565b6004810154610a3b9073ffffffffffffffffffffffffffffffffffffffff16611b04565b6004810154610a6290839073ffffffffffffffffffffffffffffffffffffffff1634611c8a565b60405134815273ffffffffffffffffffffffffffffffffffffffff83169033907f574529f953f301e05f2f1da6e9b7798bf90eef9d89647f049f43c6e8cb842c5c9060200160405180910390a35050565b610abb611f18565b610ac3611f99565b610acd8282611fe1565b610af660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b610b026121da565b73ffffffffffffffffffffffffffffffffffffffff8116610b4f576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22905f90a250565b610bc56121da565b60025473ffffffffffffffffffffffffffffffffffffffff9081169082168103610c1b576040517fdaf2d6bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560405190918316907fc4e7dd75c3c361103a75b9cc2efbd3c42ff8f20d1e60387292bb3ca1696b49eb905f90a35050565b610c98611f18565b610ca061222a565b610ca981611aa5565b610cb281612272565b6108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60098054610ce890612d48565b80601f0160208091040260200160405190810160405280929190818152602001828054610d1490612d48565b8015610d5f5780601f10610d3657610100808354040283529160200191610d5f565b820191905f5260205f20905b815481529060010190602001808311610d4257829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff8181165f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015494851660808401527401000000000000000000000000000000000000000090940460ff16151560a0830152805161014081019182905292938493909160c0840191906005840190600a9082845b815481526020019060010190808311610e0c575050509190925250505073ffffffffffffffffffffffffffffffffffffffff84165f908152600360205260408120549192509060ff1680610e84575073ffffffffffffffffffffffffffffffffffffffff84165f9081526004602052604090205460ff165b15610e9257505f9392505050565b8160a0015115610ea357505f610eb7565b60208201518251610eb49190612dc6565b90505b6040820151610ec69082612ddf565b949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546001805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682178755909216909255604051919092169283917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9190a350565b610fa56121da565b600880549082905560408051828152602081018490527f339836fabaa5f0eb442f133ec346175cc489ac04dbca653e7dd68dd1c6b56319910160405180910390a15050565b610ff26121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff1615611051576040517f70b9b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe2d01cc637b0a35c9a2dde2789da012cf2b5d14caa779d280c35209b48c31cf29190a250565b6110cf611a68565b6110d833611aa5565b6110e181611aa5565b6110ea33611b04565b6110f381611b04565b335f908152600760205260409020600181015490541461113f576040517fcf78930100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111493433611b63565b6108be338234611c8a565b60015474010000000000000000000000000000000000000000900460ff16156111a9576040517fe595c67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166111f6576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555f805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a350565b6112ad6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff161561130c576040517fd4ecc76600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f018d27189c54515c0464a9160b88974100b4ea338e1e5a16581a580cdd08c76b9190a250565b61138a6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff166113e8576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f09af5383361cf92f81a21f5147c84aed80ff6d5087bf486623c1d7c43699ab9e9190a250565b611463611a68565b61146c33611aa5565b61147533611b04565b61147e33612441565b61148733612539565b565b611491611f18565b6114996121da565b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f81146114f0576040519150601f19603f3d011682016040523d82523d5f602084013e6114f5565b606091505b5050905080611530576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518281527f104fad8a72e99cad30d4f34b4863020512b61408ab677d7f0c9eae735c31a8679060200160405180910390a1506108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61159561222a565b600a5460ff16156115d2576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155604080519182524260208301527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f591015b60405180910390a1565b611643611f18565b61164b611a68565b61165433611aa5565b61165d33612272565b61148760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61168e611f99565b6108be8161269c565b61169f6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff166116fd576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f8019d8c46c8bc3cf3019ff5b55be5dcdb8aa616d3512ad006c7dee175f090b3c9190a250565b611778611f99565b6108be81612803565b6117896121da565b600a5460ff166117c5576040517f960c07ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055604080515f81524260208201527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f59101611631565b61182a611f99565b6108be8161295d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f8115801561187d5750825b90505f8267ffffffffffffffff1660011480156118995750303b155b9050811580156118a7575080155b156118de576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561193f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b600a54610100900460ff1615611981576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560096119e58782612e3e565b506276a7006008556119f687611154565b6119fe612ac1565b8315611a5f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600a5460ff1615611487576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156108be576040517f8456d42b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff16156108be576040517fa1a04a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f03611b9c576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff1615611c17576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805483825f611c268385612ddf565b9091555050815460405173ffffffffffffffffffffffffffffffffffffffff8516917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a91611c7c91858252602082015260400190565b60405180910390a250505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611cef576040517fef99396c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611d3c576040517fe04bb5d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260076020526040902060018101548154611d719190612dc6565b821115611daa576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015473ffffffffffffffffffffffffffffffffffffffff1615801590611df05750600481015473ffffffffffffffffffffffffffffffffffffffff848116911614155b15611e27576040517f4efd913f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81816001015f828254611e3a9190612ddf565b90915550506004810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85169081179091555f9081526007602052604081206002018054849290611ea4908490612ddf565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fd39549de9e66b0b67e3696e4d033b914ea92d1fa64a28ee38da6938575214aaa84604051611f0a91815260200190565b60405180910390a350505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01611f93576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b335f9081526006602052604090205460ff16611487576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600760205260409020805482116120135781612016565b80545b915081815f015f82825461202a9190612dc6565b9091555050600481015473ffffffffffffffffffffffffffffffffffffffff16156120d55773ffffffffffffffffffffffffffffffffffffffff83165f9081526004602052604090205460ff166120bc57600481015473ffffffffffffffffffffffffffffffffffffffff165f90815260076020526040812060020180548492906120b6908490612dc6565b90915550505b81816001015f8282546120cf9190612dc6565b90915550505b6002546040515f9173ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d805f811461212c576040519150601f19603f3d011682016040523d82523d5f602084013e612131565b606091505b505090508061216c576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f4ed05e9673c26d2ed44f7ef6a7f2942df0ee3b5e1e17db4b99f9dcd261a339cd84604051611c7c91815260200190565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611487576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081526005602052604090205460ff16611487576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff166122ec576040517f5bc0da6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806003015442101561232a576040517f442c667900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f8083556004830180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556003830181905560405173ffffffffffffffffffffffffffffffffffffffff85169083908381818185875af1925050503d805f81146123b4576040519150601f19603f3d011682016040523d82523d5f602084013e6123b9565b606091505b50509050806123f4576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518381525f602082015273ffffffffffffffffffffffffffffffffffffffff8616917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a9101611c7c565b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260076020526040902060048101546001820154919216908015612533575f6001840181905573ffffffffffffffffffffffffffffffffffffffff8316815260076020526040812060020180548392906124b7908490612dc6565b90915550506004830180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560405181815273ffffffffffffffffffffffffffffffffffffffff83811691908616907f77d8b2d5629f40603353a7f0167e22f1e42d23732efdd24a8ffd477f6812e4b390602001611f0a565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604081208054909103612598576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015474010000000000000000000000000000000000000000900460ff16156125ef576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085461263d9042612ddf565b60038201819055815460408051918252602082019290925273ffffffffffffffffffffffffffffffffffffffff8416917fedc81e3c02710417110cba808754556207918ce8d29647c4b90fe924e7af3f1a910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff166126fa576040517f1dee782100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556007909152909120015416156127a65773ffffffffffffffffffffffffffffffffffffffff8082165f9081526007602052604080822080546004909101549093168252812060020180549091906127a0908490612ddf565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527ff2d07850f24dfd156502c73101307c83043b7ff3aa3191472e9a1e659050491291015b60405180910390a250565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff1615612862576040517f982b22b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff1615612898576128988161269c565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556007909152902054156128fe576128fe81612539565b61290781612441565b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527fba14e0826c92db7828c6814f979548c85017302becc8ea5ca79b6be627d1160a91016127f8565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156129bc576040517f29a2d6c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600790915290912001541615612a6b5773ffffffffffffffffffffffffffffffffffffffff8082165f908152600760205260408082208054600490910154909316825281206002018054909190612a65908490612dc6565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527f98bc7e294f14c351ce5766e9f1c1fd9e692a768b572d75ad0589496247bd8e2e91016127f8565b612ac9612ad1565b611487612b38565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16611487576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121b4612ad1565b803573ffffffffffffffffffffffffffffffffffffffff81168114612b63575f80fd5b919050565b5f60208284031215612b78575f80fd5b612b8182612b40565b9392505050565b5f8060408385031215612b99575f80fd5b612ba283612b40565b946020939093013593505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215612c13575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f8060408385031215612c58575f80fd5b612c6183612b40565b9150602083013567ffffffffffffffff811115612c7c575f80fd5b8301601f81018513612c8c575f80fd5b803567ffffffffffffffff811115612ca657612ca6612c1a565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715612d1257612d12612c1a565b604052818152828201602001871015612d29575f80fd5b816020840160208301375f602083830101528093505050509250929050565b600181811c90821680612d5c57607f821691505b602082108103612d93577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115612dd957612dd9612d99565b92915050565b80820180821115612dd957612dd9612d99565b601f821115612e3957805f5260205f20601f840160051c81016020851015612e175750805b601f840160051c820191505b81811015612e36575f8155600101612e23565b50505b505050565b815167ffffffffffffffff811115612e5857612e58612c1a565b612e6c81612e668454612d48565b84612df2565b6020601f821160018114612ebd575f8315612e875750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612e36565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612f0a5787850151825560209485019460019092019101612eea565b5084821015612f4657868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220c201e946f20e51d43fd96286bb955d49068e981a595f5bc91f595cb739b0d6a264736f6c634300081a0033

Deployed Bytecode

0x60806040526004361061025f575f3560e01c80639e1b9aa21161014b578063c76853de116100c6578063d8d9ec001161007c578063ed88c68e11610062578063ed88c68e1461026c578063f399e22e14610747578063f9f92be414610766575f80fd5b8063d8d9ec00146106fa578063e46a61b614610728575f80fd5b8063ce7cd5ad116100ac578063ce7cd5ad146106b2578063d6bd103f146106d1578063d6c89c60146106e5575f80fd5b8063c76853de14610674578063ca2a951214610693575f80fd5b8063b41a52581161011b578063b7a287ac11610101578063b7a287ac1461062d578063b81213851461064c578063bed9d86114610660575f80fd5b8063b41a5258146105fa578063b51d1d4f14610619575f80fd5b80639e1b9aa2146105755780639e48dc2b14610594578063b187bd26146105b3578063b234c544146105cc575f80fd5b806353a47bb7116101db57806386fc754c116101ab5780638da5cb5b116101915780638da5cb5b14610518578063989d1a87146105435780639c1f1f6314610562575f80fd5b806386fc754c146104f157806387c7655c146104f9575f80fd5b806353a47bb71461047157806354fd4d501461049d57806370a08231146104be57806379ba5097146104dd575f80fd5b806316934fc4116102305780631c29b8ba116102165780631c29b8ba146103e25780633b66042f146104015780634f99ef7514610452575f80fd5b806316934fc41461030657806318160ddd146103c6575f80fd5b806283b8d7146102725780630b376695146102855780630fbe82b8146102c85780631627540c146102e7575f80fd5b3661026e5761026c610794565b005b5f80fd5b61026c610280366004612b68565b6108c1565b348015610290575f80fd5b506102b361029f366004612b68565b60046020525f908152604090205460ff1681565b60405190151581526020015b60405180910390f35b3480156102d3575f80fd5b5061026c6102e2366004612b88565b610ab3565b3480156102f2575f80fd5b5061026c610301366004612b68565b610afa565b348015610311575f80fd5b50610381610320366004612b68565b60076020525f9081526040902080546001820154600283015460038401546004909401549293919290919073ffffffffffffffffffffffffffffffffffffffff81169074010000000000000000000000000000000000000000900460ff1686565b60408051968752602087019590955293850192909252606084015273ffffffffffffffffffffffffffffffffffffffff166080830152151560a082015260c0016102bf565b3480156103d1575f80fd5b50475b6040519081526020016102bf565b3480156103ed575f80fd5b5061026c6103fc366004612b68565b610bbd565b34801561040c575f80fd5b5060025461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102bf565b34801561045d575f80fd5b5061026c61046c366004612b68565b610c90565b34801561047c575f80fd5b5060015461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156104a8575f80fd5b506104b1610cdb565b6040516102bf9190612bb0565b3480156104c9575f80fd5b506103d46104d8366004612b68565b610d67565b3480156104e8575f80fd5b5061026c610ece565b61026c610794565b348015610504575f80fd5b5061026c610513366004612c03565b610f9d565b348015610523575f80fd5b505f5461042d9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561054e575f80fd5b5061026c61055d366004612b68565b610fea565b61026c610570366004612b68565b6110c7565b348015610580575f80fd5b5061026c61058f366004612b68565b611154565b34801561059f575f80fd5b5061026c6105ae366004612b68565b6112a5565b3480156105be575f80fd5b50600a546102b39060ff1681565b3480156105d7575f80fd5b506102b36105e6366004612b68565b60066020525f908152604090205460ff1681565b348015610605575f80fd5b5061026c610614366004612b68565b611382565b348015610624575f80fd5b5061026c61145b565b348015610638575f80fd5b5061026c610647366004612c03565b611489565b348015610657575f80fd5b5061026c61158d565b34801561066b575f80fd5b5061026c61163b565b34801561067f575f80fd5b5061026c61068e366004612b68565b611686565b34801561069e575f80fd5b5061026c6106ad366004612b68565b611697565b3480156106bd575f80fd5b5061026c6106cc366004612b68565b611770565b3480156106dc575f80fd5b5061026c611781565b3480156106f0575f80fd5b506103d460085481565b348015610705575f80fd5b506102b3610714366004612b68565b60056020525f908152604090205460ff1681565b348015610733575f80fd5b5061026c610742366004612b68565b611822565b348015610752575f80fd5b5061026c610761366004612c47565b611833565b348015610771575f80fd5b506102b3610780366004612b68565b60036020525f908152604090205460ff1681565b61079c611a68565b6107a533611aa5565b6107ae33611b04565b6107b83433611b63565b335f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015473ffffffffffffffffffffffffffffffffffffffff8116608085015274010000000000000000000000000000000000000000900460ff16151560a08401528151610140810192839052909160c0840191906005840190600a9082845b8154815260200190600101908083116108555750505091909252505050608081015190915073ffffffffffffffffffffffffffffffffffffffff16156108be576108a28160800151611aa5565b6108af8160800151611b04565b6108be33826080015134611c8a565b50565b6108c9611a68565b6108d281611aa5565b6108db81611b04565b345f03610914576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff161561098f576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f036109c9576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6109d33483611b63565b600481015473ffffffffffffffffffffffffffffffffffffffff1615610a62576004810154610a179073ffffffffffffffffffffffffffffffffffffffff16611aa5565b6004810154610a3b9073ffffffffffffffffffffffffffffffffffffffff16611b04565b6004810154610a6290839073ffffffffffffffffffffffffffffffffffffffff1634611c8a565b60405134815273ffffffffffffffffffffffffffffffffffffffff83169033907f574529f953f301e05f2f1da6e9b7798bf90eef9d89647f049f43c6e8cb842c5c9060200160405180910390a35050565b610abb611f18565b610ac3611f99565b610acd8282611fe1565b610af660017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050565b610b026121da565b73ffffffffffffffffffffffffffffffffffffffff8116610b4f576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22905f90a250565b610bc56121da565b60025473ffffffffffffffffffffffffffffffffffffffff9081169082168103610c1b576040517fdaf2d6bb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84811691821790925560405190918316907fc4e7dd75c3c361103a75b9cc2efbd3c42ff8f20d1e60387292bb3ca1696b49eb905f90a35050565b610c98611f18565b610ca061222a565b610ca981611aa5565b610cb281612272565b6108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b60098054610ce890612d48565b80601f0160208091040260200160405190810160405280929190818152602001828054610d1490612d48565b8015610d5f5780601f10610d3657610100808354040283529160200191610d5f565b820191905f5260205f20905b815481529060010190602001808311610d4257829003601f168201915b505050505081565b73ffffffffffffffffffffffffffffffffffffffff8181165f908152600760209081526040808320815160e0810183528154815260018201549381019390935260028101548383015260038101546060840152600481015494851660808401527401000000000000000000000000000000000000000090940460ff16151560a0830152805161014081019182905292938493909160c0840191906005840190600a9082845b815481526020019060010190808311610e0c575050509190925250505073ffffffffffffffffffffffffffffffffffffffff84165f908152600360205260408120549192509060ff1680610e84575073ffffffffffffffffffffffffffffffffffffffff84165f9081526004602052604090205460ff165b15610e9257505f9392505050565b8160a0015115610ea357505f610eb7565b60208201518251610eb49190612dc6565b90505b6040820151610ec69082612ddf565b949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610f1f576040517fd74b334e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80546001805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682178755909216909255604051919092169283917fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c9190a350565b610fa56121da565b600880549082905560408051828152602081018490527f339836fabaa5f0eb442f133ec346175cc489ac04dbca653e7dd68dd1c6b56319910160405180910390a15050565b610ff26121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff1615611051576040517f70b9b0d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517fe2d01cc637b0a35c9a2dde2789da012cf2b5d14caa779d280c35209b48c31cf29190a250565b6110cf611a68565b6110d833611aa5565b6110e181611aa5565b6110ea33611b04565b6110f381611b04565b335f908152600760205260409020600181015490541461113f576040517fcf78930100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111493433611b63565b6108be338234611c8a565b60015474010000000000000000000000000000000000000000900460ff16156111a9576040517fe595c67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166111f6576040517fc81abf6000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000001790555f805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811782556040519091907fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c908290a350565b6112ad6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff161561130c576040517fd4ecc76600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055517f018d27189c54515c0464a9160b88974100b4ea338e1e5a16581a580cdd08c76b9190a250565b61138a6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526005602052604090205460ff166113e8576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526005602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f09af5383361cf92f81a21f5147c84aed80ff6d5087bf486623c1d7c43699ab9e9190a250565b611463611a68565b61146c33611aa5565b61147533611b04565b61147e33612441565b61148733612539565b565b611491611f18565b6114996121da565b5f805460405173ffffffffffffffffffffffffffffffffffffffff9091169083908381818185875af1925050503d805f81146114f0576040519150601f19603f3d011682016040523d82523d5f602084013e6114f5565b606091505b5050905080611530576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040518281527f104fad8a72e99cad30d4f34b4863020512b61408ab677d7f0c9eae735c31a8679060200160405180910390a1506108be60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61159561222a565b600a5460ff16156115d2576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155604080519182524260208301527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f591015b60405180910390a1565b611643611f18565b61164b611a68565b61165433611aa5565b61165d33612272565b61148760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b61168e611f99565b6108be8161269c565b61169f6121da565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526006602052604090205460ff166116fd576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f8181526006602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f8019d8c46c8bc3cf3019ff5b55be5dcdb8aa616d3512ad006c7dee175f090b3c9190a250565b611778611f99565b6108be81612803565b6117896121da565b600a5460ff166117c5576040517f960c07ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055604080515f81524260208201527f5297bdbba6a0f5b1f239889b8bd6040ef096d48d0568711dd5dfa1c31607a8f59101611631565b61182a611f99565b6108be8161295d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000810460ff16159067ffffffffffffffff165f8115801561187d5750825b90505f8267ffffffffffffffff1660011480156118995750303b155b9050811580156118a7575080155b156118de576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561193f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b600a54610100900460ff1615611981576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16610100179055600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead17905560096119e58782612e3e565b506276a7006008556119f687611154565b6119fe612ac1565b8315611a5f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600a5460ff1615611487576040517fab35696f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156108be576040517f8456d42b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff16156108be576040517fa1a04a3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815f03611b9c576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff1615611c17576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805483825f611c268385612ddf565b9091555050815460405173ffffffffffffffffffffffffffffffffffffffff8516917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a91611c7c91858252602082015260400190565b60405180910390a250505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611cef576040517fef99396c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216611d3c576040517fe04bb5d900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260076020526040902060018101548154611d719190612dc6565b821115611daa576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015473ffffffffffffffffffffffffffffffffffffffff1615801590611df05750600481015473ffffffffffffffffffffffffffffffffffffffff848116911614155b15611e27576040517f4efd913f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81816001015f828254611e3a9190612ddf565b90915550506004810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85169081179091555f9081526007602052604081206002018054849290611ea4908490612ddf565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fd39549de9e66b0b67e3696e4d033b914ea92d1fa64a28ee38da6938575214aaa84604051611f0a91815260200190565b60405180910390a350505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0080547ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01611f93576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60029055565b335f9081526006602052604090205460ff16611487576040517facceb67400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152600760205260409020805482116120135781612016565b80545b915081815f015f82825461202a9190612dc6565b9091555050600481015473ffffffffffffffffffffffffffffffffffffffff16156120d55773ffffffffffffffffffffffffffffffffffffffff83165f9081526004602052604090205460ff166120bc57600481015473ffffffffffffffffffffffffffffffffffffffff165f90815260076020526040812060020180548492906120b6908490612dc6565b90915550505b81816001015f8282546120cf9190612dc6565b90915550505b6002546040515f9173ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d805f811461212c576040519150601f19603f3d011682016040523d82523d5f602084013e612131565b606091505b505090508061216c576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff167f4ed05e9673c26d2ed44f7ef6a7f2942df0ee3b5e1e17db4b99f9dcd261a339cd84604051611c7c91815260200190565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f5473ffffffffffffffffffffffffffffffffffffffff163314611487576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b335f9081526005602052604090205460ff16611487576040517fd56b8a2000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600760205260409020600481015474010000000000000000000000000000000000000000900460ff166122ec576040517f5bc0da6800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806003015442101561232a576040517f442c667900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80545f8083556004830180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690556003830181905560405173ffffffffffffffffffffffffffffffffffffffff85169083908381818185875af1925050503d805f81146123b4576040519150601f19603f3d011682016040523d82523d5f602084013e6123b9565b606091505b50509050806123f4576040517f90b8ec1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080518381525f602082015273ffffffffffffffffffffffffffffffffffffffff8616917ff3ee618df6e6ff5a26ef25cf1ba9bc24b56492f5ff29acf2815121a2b903138a9101611c7c565b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260076020526040902060048101546001820154919216908015612533575f6001840181905573ffffffffffffffffffffffffffffffffffffffff8316815260076020526040812060020180548392906124b7908490612dc6565b90915550506004830180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905560405181815273ffffffffffffffffffffffffffffffffffffffff83811691908616907f77d8b2d5629f40603353a7f0167e22f1e42d23732efdd24a8ffd477f6812e4b390602001611f0a565b50505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526007602052604081208054909103612598576040517f040ef8ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600481015474010000000000000000000000000000000000000000900460ff16156125ef576040517fd206192300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000017905560085461263d9042612ddf565b60038201819055815460408051918252602082019290925273ffffffffffffffffffffffffffffffffffffffff8416917fedc81e3c02710417110cba808754556207918ce8d29647c4b90fe924e7af3f1a910160405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff166126fa576040517f1dee782100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556007909152909120015416156127a65773ffffffffffffffffffffffffffffffffffffffff8082165f9081526007602052604080822080546004909101549093168252812060020180549091906127a0908490612ddf565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527ff2d07850f24dfd156502c73101307c83043b7ff3aa3191472e9a1e659050491291015b60405180910390a250565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526003602052604090205460ff1615612862576040517f982b22b100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff1615612898576128988161269c565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260036020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556007909152902054156128fe576128fe81612539565b61290781612441565b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527fba14e0826c92db7828c6814f979548c85017302becc8ea5ca79b6be627d1160a91016127f8565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16156129bc576040517f29a2d6c000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8082165f90815260046020818152604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055600790915290912001541615612a6b5773ffffffffffffffffffffffffffffffffffffffff8082165f908152600760205260408082208054600490910154909316825281206002018054909190612a65908490612dc6565b90915550505b73ffffffffffffffffffffffffffffffffffffffff81165f818152600760209081526040918290205491519182527f98bc7e294f14c351ce5766e9f1c1fd9e692a768b572d75ad0589496247bd8e2e91016127f8565b612ac9612ad1565b611487612b38565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005468010000000000000000900460ff16611487576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121b4612ad1565b803573ffffffffffffffffffffffffffffffffffffffff81168114612b63575f80fd5b919050565b5f60208284031215612b78575f80fd5b612b8182612b40565b9392505050565b5f8060408385031215612b99575f80fd5b612ba283612b40565b946020939093013593505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f60208284031215612c13575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f8060408385031215612c58575f80fd5b612c6183612b40565b9150602083013567ffffffffffffffff811115612c7c575f80fd5b8301601f81018513612c8c575f80fd5b803567ffffffffffffffff811115612ca657612ca6612c1a565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715612d1257612d12612c1a565b604052818152828201602001871015612d29575f80fd5b816020840160208301375f602083830101528093505050509250929050565b600181811c90821680612d5c57607f821691505b602082108103612d93577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b81810381811115612dd957612dd9612d99565b92915050565b80820180821115612dd957612dd9612d99565b601f821115612e3957805f5260205f20601f840160051c81016020851015612e175750805b601f840160051c820191505b81811015612e36575f8155600101612e23565b50505b505050565b815167ffffffffffffffff811115612e5857612e58612c1a565b612e6c81612e668454612d48565b84612df2565b6020601f821160018114612ebd575f8315612e875750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455612e36565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b82811015612f0a5787850151825560209485019460019092019101612eea565b5084821015612f4657868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220c201e946f20e51d43fd96286bb955d49068e981a595f5bc91f595cb739b0d6a264736f6c634300081a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.