ETH Price: $2,071.95 (-5.22%)

Contract

0x5a5CE8C4DD8A6cb99D4efDb4d400d3abd760C730
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
-140108052022-01-15 15:17:341530 days ago1642259854  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StakefishServicesContract

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion
File 1 of 4 : StakefishServicesContract.sol
// Copyright (C) 2021 BITFISH LIMITED

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-only

pragma solidity 0.8.4;

import "./interfaces/deposit_contract.sol";
import "./interfaces/IStakefishServicesContract.sol";
import "./libraries/Address.sol";

contract StakefishServicesContract is IStakefishServicesContract {
    using Address for address payable;

    uint256 private constant HOUR = 3600;
    uint256 private constant DAY = 24 * HOUR;
    uint256 private constant WEEK = 7 * DAY;
    uint256 private constant YEAR = 365 * DAY;
    uint256 private constant MAX_SECONDS_IN_EXIT_QUEUE = 1 * YEAR;
    uint256 private constant COMMISSION_RATE_SCALE = 1000000;

    // Packed into a single slot
    uint24 private _commissionRate;
    address private _operatorAddress;
    uint64 private _exitDate;
    State private _state;

    bytes32 private _operatorDataCommitment;

    mapping(address => mapping(address => uint256)) private _allowances;
    mapping(address => mapping(address => uint256)) private _allowedWithdrawals;
    mapping(address => uint256) private _deposits;
    uint256 private _totalDeposits;
    uint256 private _operatorClaimable;

    IDepositContract public constant depositContract =
        IDepositContract(0x00000000219ab540356cBB839Cbe05303d7705Fa);

    modifier onlyOperator() {
        require(
            msg.sender == _operatorAddress,
            "Caller is not the operator"
        );
        _;
    }

    modifier initializer() {
        require(
            _state == State.NotInitialized,
            "Contract is already initialized"
        );
        _state = State.PreDeposit;
        _;
    }

    function initialize(
        uint24 commissionRate,
        address operatorAddress,
        bytes32 operatorDataCommitment
    )
        external
        initializer
    {
        require(uint256(commissionRate) <= COMMISSION_RATE_SCALE, "Commission rate exceeds scale");

        _commissionRate = commissionRate;
        _operatorAddress = operatorAddress;
        _operatorDataCommitment = operatorDataCommitment;
    }

    receive() payable external {
        if (_state == State.PreDeposit) {
            revert("Plain Ether transfer not allowed");
        }
    }

    function updateExitDate(uint64 newExitDate)
        external
        override
        onlyOperator
    {
        require(
            _state == State.PostDeposit,
            "Validator is not active"
        );

        require(
            newExitDate < _exitDate,
            "Not earlier than the original value"
        );

        _exitDate = newExitDate;
    }

    function createValidator(
        bytes calldata validatorPubKey, // 48 bytes
        bytes calldata depositSignature, // 96 bytes
        bytes32 depositDataRoot,
        uint64 exitDate
    )
        external
        override
        onlyOperator
    {

        require(_state == State.PreDeposit, "Validator has been created");
        _state = State.PostDeposit;

        require(validatorPubKey.length == 48, "Invalid validator public key");
        require(depositSignature.length == 96, "Invalid deposit signature");
        require(_operatorDataCommitment == keccak256(
            abi.encodePacked(
                address(this),
                validatorPubKey,
                depositSignature,
                depositDataRoot,
                exitDate
            )
        ), "Data doesn't match commitment");

        _exitDate = exitDate;

        depositContract.deposit{value: 32 ether}(
            validatorPubKey,
            abi.encodePacked(uint96(0x010000000000000000000000), address(this)),
            depositSignature,
            depositDataRoot
        );

        emit ValidatorDeposited(validatorPubKey);
    }

    function deposit()
        external
        payable
        override
        returns (uint256 surplus)
    {
        require(
            _state == State.PreDeposit,
            "Validator already created"
        );

        return _handleDeposit(msg.sender);
    }

    function depositOnBehalfOf(address depositor)
        external
        payable
        override
        returns (uint256 surplus)
    {
        require(
            _state == State.PreDeposit,
            "Validator already created"
        );
        return _handleDeposit(depositor);
    }

    function endOperatorServices()
        external
        override
    {
        uint256 balance = address(this).balance;
        require(balance > 0, "Can't end with 0 balance");
        require(_state == State.PostDeposit, "Not allowed in the current state");
        require((msg.sender == _operatorAddress && block.timestamp > _exitDate) ||
                (_deposits[msg.sender] > 0 && block.timestamp > _exitDate + MAX_SECONDS_IN_EXIT_QUEUE), "Not allowed at the current time");

        _state = State.Withdrawn;

        if (balance > 32 ether) {
            uint256 profit = balance - 32 ether;
            uint256 finalCommission = profit * _commissionRate / COMMISSION_RATE_SCALE;
            _operatorClaimable += finalCommission;
        }

        emit ServiceEnd();
    }

    function operatorClaim()
        external
        override
        onlyOperator
        returns (uint256)
    {
        uint256 claimable = _operatorClaimable;
        if (claimable > 0) {
            _operatorClaimable = 0;
            payable(_operatorAddress).sendValue(claimable);

            emit Claim(_operatorAddress, claimable);
        }

        return claimable;
    }

    string private constant WITHDRAWALS_NOT_ALLOWED =
        "Not allowed when validator is active";

    function withdrawAll(uint256 minimumETHAmount)
        external
        override
        returns (uint256)
    {
        require(_state != State.PostDeposit, WITHDRAWALS_NOT_ALLOWED);
        uint256 value = _executeWithdrawal(msg.sender, payable(msg.sender), _deposits[msg.sender]);
        require(value >= minimumETHAmount, "Less than minimum amount");
        return value;
    }

    function withdraw(
        uint256 amount,
        uint256 minimumETHAmount
    )
        external
        override
        returns (uint256)
    {
        require(_state != State.PostDeposit, WITHDRAWALS_NOT_ALLOWED);
        uint256 value = _executeWithdrawal(msg.sender, payable(msg.sender), amount);
        require(value >= minimumETHAmount, "Less than minimum amount");
        return value;
    }

    function withdrawTo(
        uint256 amount,
        address payable beneficiary,
        uint256 minimumETHAmount
    )
        external
        override
        returns (uint256)
    {
        require(_state != State.PostDeposit, WITHDRAWALS_NOT_ALLOWED);
        uint256 value = _executeWithdrawal(msg.sender, beneficiary, amount);
        require(value >= minimumETHAmount, "Less than minimum amount");
        return value;
    }

    function approve(
        address spender,
        uint256 amount
    )
        public
        override
        returns (bool)
    {
        _approve(msg.sender, spender, amount);
        return true;
    }

    function increaseAllowance(
        address spender,
        uint256 addedValue
    )
        external
        override
        returns (bool)
    {
        _approve(msg.sender, spender, _allowances[msg.sender][spender] + addedValue);
        return true;
    }

    function decreaseAllowance(
        address spender,
        uint256 subtractedValue
    )
        external
        override
        returns (bool)
    {
        _approve(msg.sender, spender, _allowances[msg.sender][spender] - subtractedValue);
        return true;
    }

    function forceDecreaseAllowance(
        address spender,
        uint256 subtractedValue
    )
        external
        override
        returns (bool)
    {
        uint256 currentAllowance = _allowances[msg.sender][spender];
        _approve(msg.sender, spender, currentAllowance - _min(subtractedValue, currentAllowance));
        return true;
    }

    function approveWithdrawal(
        address spender,
        uint256 amount
    )
        external
        override
        returns (bool)
    {
        _approveWithdrawal(msg.sender, spender, amount);
        return true;
    }

    function increaseWithdrawalAllowance(
        address spender,
        uint256 addedValue
    )
        external
        override
        returns (bool)
    {
        _approveWithdrawal(msg.sender, spender, _allowedWithdrawals[msg.sender][spender] + addedValue);
        return true;
    }

    function decreaseWithdrawalAllowance(
        address spender,
        uint256 subtractedValue
    )
        external
        override
        returns (bool)
    {
        _approveWithdrawal(msg.sender, spender, _allowedWithdrawals[msg.sender][spender] - subtractedValue);
        return true;
    }

    function forceDecreaseWithdrawalAllowance(
        address spender,
        uint256 subtractedValue
    )
        external
        override
        returns (bool)
    {
        uint256 currentAllowance = _allowedWithdrawals[msg.sender][spender];
        _approveWithdrawal(msg.sender, spender, currentAllowance - _min(subtractedValue, currentAllowance));
        return true;
    }

    function withdrawFrom(
        address depositor,
        address payable beneficiary,
        uint256 amount,
        uint256 minimumETHAmount
    )
        external
        override
        returns (uint256)
    {
        require(_state != State.PostDeposit, WITHDRAWALS_NOT_ALLOWED);
        uint256 spenderAllowance = _allowedWithdrawals[depositor][msg.sender];
        uint256 newAllowance = spenderAllowance - amount;
        // Please note that there is no need to require(_deposit <= spenderAllowance)
        // here because modern versions of Solidity insert underflow checks
        _allowedWithdrawals[depositor][msg.sender] = newAllowance;
        emit WithdrawalApproval(depositor, msg.sender, newAllowance);

        uint256 value = _executeWithdrawal(depositor, beneficiary, amount);
        require(value >= minimumETHAmount, "Less than minimum amount");
        return value; 
    }

    function transferDeposit(
        address to,
        uint256 amount
    )
        external
        override
        returns (bool)
    {
        _transfer(msg.sender, to, amount);
        return true;
    }

    function transferDepositFrom(
        address from,
        address to,
        uint256 amount
    )
        external
        override
        returns (bool)
    {
        uint256 currentAllowance = _allowances[from][msg.sender];

        _approve(from, msg.sender, currentAllowance - amount);
        _transfer(from, to, amount);

        return true;
    }

    function withdrawalAllowance(
        address depositor,
        address spender
    )
        external
        view
        override
        returns (uint256)
    {
        return _allowedWithdrawals[depositor][spender];
    }

    function getCommissionRate()
        external
        view
        override
        returns (uint256)
    {
        return _commissionRate;
    }

    function getExitDate()
        external
        view
        override
        returns (uint256)
    {
        return _exitDate;
    }

    function getState()
        external
        view
        override
        returns(State)
    {
        return _state;
    }

    function getOperatorAddress()
        external
        view
        override
        returns (address)
    {
        return _operatorAddress;
    }

    function getDeposit(address depositor)
        external
        view
        override
        returns (uint256)
    {
        return _deposits[depositor];
    }

    function getTotalDeposits()
        external
        view
        override
        returns (uint256)
    {
        return _totalDeposits;
    }

    function getAllowance(
        address owner,
        address spender
    )
        external
        view
        override
        returns (uint256)
    {
        return _allowances[owner][spender];
    }

    function getOperatorDataCommitment()
        external
        view
        override
        returns (bytes32)
    {
        return _operatorDataCommitment;
    }

    function getOperatorClaimable()
        external
        view
        override
        returns (uint256)
    {
        return _operatorClaimable;
    }

    function getWithdrawableAmount(address owner)
        external
        view
        override
        returns (uint256)
    {
        if (_state == State.PostDeposit) {
            return 0;
        }

        return _deposits[owner] * (address(this).balance - _operatorClaimable) / _totalDeposits;
    }

    function _executeWithdrawal(
        address depositor,
        address payable beneficiary,
        uint256 amount
    )
        internal
        returns (uint256)
    {
        require(amount > 0, "Amount shouldn't be zero");

        uint256 value = amount * (address(this).balance - _operatorClaimable) / _totalDeposits;
        // Modern versions of Solidity automatically add underflow checks,
        // so we don't need to `require(_deposits[_depositor] < _deposit` here:
        _deposits[depositor] -= amount;
        _totalDeposits -= amount;
        emit Withdrawal(depositor, beneficiary, amount, value);
        payable(beneficiary).sendValue(value);

        return value;
    }

    // NOTE: This throws (on underflow) if the contract's balance was more than
    // 32 ether before the call
    function _handleDeposit(address depositor)
        internal
        returns (uint256 surplus)
    {
        uint256 depositSize = msg.value;
        surplus = (address(this).balance > 32 ether) ?
            (address(this).balance - 32 ether) : 0;

        uint256 acceptedDeposit = depositSize - surplus;

        _deposits[depositor] += acceptedDeposit;
        _totalDeposits += acceptedDeposit;

        emit Deposit(depositor, acceptedDeposit);
        
        if (surplus > 0) {
            payable(depositor).sendValue(surplus);
        }
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    )
        internal
    {
        require(to != address(0), "Transfer to the zero address");

        _deposits[from] -= amount;
        _deposits[to] += amount;

        emit Transfer(from, to, amount);
    }

    function _approve(
        address owner,
        address spender,
        uint256 amount
    )
        internal
    {
        require(spender != address(0), "Approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function _approveWithdrawal(
        address owner,
        address spender,
        uint256 amount
    )
        internal
    {
        require(spender != address(0), "Approve to the zero address");

        _allowedWithdrawals[owner][spender] = amount;
        emit WithdrawalApproval(owner, spender, amount);
    }

    function _min(
        uint256 a,
        uint256 b
    )
        internal
        pure
        returns (uint256)
    {
        return a < b ? a : b;
    }
}

// ┏━━━┓━┏┓━┏┓━━┏━━━┓━━┏━━━┓━━━━┏━━━┓━━━━━━━━━━━━━━━━━━━┏┓━━━━━┏━━━┓━━━━━━━━━┏┓━━━━━━━━━━━━━━┏┓━
// ┃┏━━┛┏┛┗┓┃┃━━┃┏━┓┃━━┃┏━┓┃━━━━┗┓┏┓┃━━━━━━━━━━━━━━━━━━┏┛┗┓━━━━┃┏━┓┃━━━━━━━━┏┛┗┓━━━━━━━━━━━━┏┛┗┓
// ┃┗━━┓┗┓┏┛┃┗━┓┗┛┏┛┃━━┃┃━┃┃━━━━━┃┃┃┃┏━━┓┏━━┓┏━━┓┏━━┓┏┓┗┓┏┛━━━━┃┃━┗┛┏━━┓┏━┓━┗┓┏┛┏━┓┏━━┓━┏━━┓┗┓┏┛
// ┃┏━━┛━┃┃━┃┏┓┃┏━┛┏┛━━┃┃━┃┃━━━━━┃┃┃┃┃┏┓┃┃┏┓┃┃┏┓┃┃━━┫┣┫━┃┃━━━━━┃┃━┏┓┃┏┓┃┃┏┓┓━┃┃━┃┏┛┗━┓┃━┃┏━┛━┃┃━
// ┃┗━━┓━┃┗┓┃┃┃┃┃┃┗━┓┏┓┃┗━┛┃━━━━┏┛┗┛┃┃┃━┫┃┗┛┃┃┗┛┃┣━━┃┃┃━┃┗┓━━━━┃┗━┛┃┃┗┛┃┃┃┃┃━┃┗┓┃┃━┃┗┛┗┓┃┗━┓━┃┗┓
// ┗━━━┛━┗━┛┗┛┗┛┗━━━┛┗┛┗━━━┛━━━━┗━━━┛┗━━┛┃┏━┛┗━━┛┗━━┛┗┛━┗━┛━━━━┗━━━┛┗━━┛┗┛┗┛━┗━┛┗┛━┗━━━┛┗━━┛━┗━┛
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┃┃━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┗┛━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

// SPDX-License-Identifier: CC0-1.0

pragma solidity 0.8.4;

// This interface is designed to be compatible with the Vyper version.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
interface IDepositContract {
    /// @notice A processed deposit event.
    event DepositEvent(
        bytes pubkey,
        bytes withdrawal_credentials,
        bytes amount,
        bytes signature,
        bytes index
    );

    /// @notice Submit a Phase 0 DepositData object.
    /// @param pubkey A BLS12-381 public key.
    /// @param withdrawal_credentials Commitment to a public key for withdrawals.
    /// @param signature A BLS12-381 signature.
    /// @param deposit_data_root The SHA-256 hash of the SSZ-encoded DepositData object.
    /// Used as a protection against malformed input.
    function deposit(
        bytes calldata pubkey,
        bytes calldata withdrawal_credentials,
        bytes calldata signature,
        bytes32 deposit_data_root
    ) external payable;

    /// @notice Query the current deposit root hash.
    /// @return The deposit root hash.
    function get_deposit_root() external view returns (bytes32);

    /// @notice Query the current deposit count.
    /// @return The deposit count encoded as a little endian 64-bit number.
    function get_deposit_count() external view returns (bytes memory);
}

// Based on official specification in https://eips.ethereum.org/EIPS/eip-165
interface ERC165 {
    /// @notice Query if a contract implements an interface
    /// @param interfaceId The interface identifier, as specified in ERC-165
    /// @dev Interface identification is specified in ERC-165. This function
    ///  uses less than 30,000 gas.
    /// @return `true` if the contract implements `interfaceId` and
    ///  `interfaceId` is not 0xffffffff, `false` otherwise
    function supportsInterface(bytes4 interfaceId) external pure returns (bool);
}

// This is a rewrite of the Vyper Eth2.0 deposit contract in Solidity.
// It tries to stay as close as possible to the original source code.
/// @notice This is the Ethereum 2.0 deposit contract interface.
/// For more information see the Phase 0 specification under https://github.com/ethereum/eth2.0-specs
contract DepositContract is IDepositContract, ERC165 {
    uint constant DEPOSIT_CONTRACT_TREE_DEPTH = 32;
    // NOTE: this also ensures `deposit_count` will fit into 64-bits
    uint constant MAX_DEPOSIT_COUNT = 2**DEPOSIT_CONTRACT_TREE_DEPTH - 1;

    bytes32[DEPOSIT_CONTRACT_TREE_DEPTH] branch;
    uint256 deposit_count;

    bytes32[DEPOSIT_CONTRACT_TREE_DEPTH] zero_hashes;

    constructor() {
        // Compute hashes in empty sparse Merkle tree
        for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH - 1; height++)
            zero_hashes[height + 1] = sha256(abi.encodePacked(zero_hashes[height], zero_hashes[height]));
    }

    function get_deposit_root() override external view returns (bytes32) {
        bytes32 node;
        uint size = deposit_count;
        for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
            if ((size & 1) == 1)
                node = sha256(abi.encodePacked(branch[height], node));
            else
                node = sha256(abi.encodePacked(node, zero_hashes[height]));
            size /= 2;
        }
        return sha256(abi.encodePacked(
            node,
            to_little_endian_64(uint64(deposit_count)),
            bytes24(0)
        ));
    }

    function get_deposit_count() override external view returns (bytes memory) {
        return to_little_endian_64(uint64(deposit_count));
    }

    function deposit(
        bytes calldata pubkey,
        bytes calldata withdrawal_credentials,
        bytes calldata signature,
        bytes32 deposit_data_root
    ) override external payable {
        // Extended ABI length checks since dynamic types are used.
        require(pubkey.length == 48, "DepositContract: invalid pubkey length");
        require(withdrawal_credentials.length == 32, "DepositContract: invalid withdrawal_credentials length");
        require(signature.length == 96, "DepositContract: invalid signature length");

        // Check deposit amount
        require(msg.value >= 1 ether, "DepositContract: deposit value too low");
        require(msg.value % 1 gwei == 0, "DepositContract: deposit value not multiple of gwei");
        uint deposit_amount = msg.value / 1 gwei;
        require(deposit_amount <= type(uint64).max, "DepositContract: deposit value too high");

        // Emit `DepositEvent` log
        bytes memory amount = to_little_endian_64(uint64(deposit_amount));
        emit DepositEvent(
            pubkey,
            withdrawal_credentials,
            amount,
            signature,
            to_little_endian_64(uint64(deposit_count))
        );

        // Compute deposit data root (`DepositData` hash tree root)
        bytes32 pubkey_root = sha256(abi.encodePacked(pubkey, bytes16(0)));
        bytes32 signature_root = sha256(abi.encodePacked(
            sha256(abi.encodePacked(signature[:64])),
            sha256(abi.encodePacked(signature[64:], bytes32(0)))
        ));
        bytes32 node = sha256(abi.encodePacked(
            sha256(abi.encodePacked(pubkey_root, withdrawal_credentials)),
            sha256(abi.encodePacked(amount, bytes24(0), signature_root))
        ));

        // Verify computed and expected deposit data roots match
        require(node == deposit_data_root, "DepositContract: reconstructed DepositData does not match supplied deposit_data_root");

        // Avoid overflowing the Merkle tree (and prevent edge case in computing `branch`)
        require(deposit_count < MAX_DEPOSIT_COUNT, "DepositContract: merkle tree full");

        // Add deposit data root to Merkle tree (update a single `branch` node)
        deposit_count += 1;
        uint size = deposit_count;
        for (uint height = 0; height < DEPOSIT_CONTRACT_TREE_DEPTH; height++) {
            if ((size & 1) == 1) {
                branch[height] = node;
                return;
            }
            node = sha256(abi.encodePacked(branch[height], node));
            size /= 2;
        }
        // As the loop should always end prematurely with the `return` statement,
        // this code should be unreachable. We assert `false` just to be safe.
        assert(false);
    }

    function supportsInterface(bytes4 interfaceId) override external pure returns (bool) {
        return interfaceId == type(ERC165).interfaceId || interfaceId == type(IDepositContract).interfaceId;
    }

    function to_little_endian_64(uint64 value) internal pure returns (bytes memory ret) {
        ret = new bytes(8);
        bytes8 bytesValue = bytes8(value);
        // Byteswapping during copying to bytes.
        ret[0] = bytesValue[7];
        ret[1] = bytesValue[6];
        ret[2] = bytesValue[5];
        ret[3] = bytesValue[4];
        ret[4] = bytesValue[3];
        ret[5] = bytesValue[2];
        ret[6] = bytesValue[1];
        ret[7] = bytesValue[0];
    }
}

// Copyright (C) 2021 BITFISH LIMITED

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// SPDX-License-Identifier: GPL-3.0-only


pragma solidity ^0.8.0;

/// @notice Governs the life cycle of a single Eth2 validator with ETH provided by multiple stakers.
interface IStakefishServicesContract {
    /// @notice The life cycle of a services contract.
    enum State {
        NotInitialized,
        PreDeposit,
        PostDeposit,
        Withdrawn
    }

    /// @notice Emitted when a `spender` is set to allow the transfer of an `owner`'s deposit stake amount.
    /// `amount` is the new allownace.
    /// @dev Also emitted when {transferDepositFrom} is called.
    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 amount
    );

    /// @notice Emitted when deposit stake amount is transferred.
    /// @param from The address of deposit stake owner.
    /// @param to The address of deposit stake beneficiary.
    /// @param amount The amount of transferred deposit stake.
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 amount
    );

    /// @notice Emitted when a `spender` is set to allow withdrawal on behalf of a `owner`.
    /// `amount` is the new allowance.
    /// @dev Also emitted when {WithdrawFrom} is called.
    event WithdrawalApproval(
        address indexed owner,
        address indexed spender,
        uint256 amount
    );

    /// @notice Emitted when `owner`'s ETH are withdrawan to `to`.
    /// @param owner The address of deposit stake owner.
    /// @param to The address of ETH beneficiary.
    /// @param amount The amount of deposit stake to be converted to ETH.
    /// @param value The amount of withdrawn ETH.
    event Withdrawal(
        address indexed owner,
        address indexed to,
        uint256 amount,
        uint256 value
    );

    /// @notice Emitted when 32 ETH is transferred to the eth2 deposit contract.
    /// @param pubkey A BLS12-381 public key.
    event ValidatorDeposited(
        bytes pubkey // 48 bytes
    );

    /// @notice Emitted when a validator exits and the operator settles the commission.
    event ServiceEnd();

    /// @notice Emitted when deposit to the services contract.
    /// @param from The address of the deposit stake owner.
    /// @param amount The accepted amount of ETH deposited into the services contract.
    event Deposit(
        address from,
        uint256 amount
    );

    /// @notice Emitted when operaotr claims commission fee.
    /// @param receiver The address of the operator.
    /// @param amount The amount of ETH sent to the operator address.
    event Claim(
        address receiver,
        uint256 amount
    );

    /// @notice Updates the exit date of the validator.
    /// @dev The exit date should be in the range of uint64.
    /// @param newExitDate The new exit date should come before the previously specified exit date.
    function updateExitDate(uint64 newExitDate) external;

    /// @notice Submits a Phase 0 DepositData to the eth2 deposit contract.
    /// @dev The Keccak hash of the contract address and all submitted data should match the `_operatorDataCommitment`.
    /// Emits a {ValidatorDeposited} event.
    /// @param validatorPubKey A BLS12-381 public key.
    /// @param depositSignature A BLS12-381 signature.
    /// @param depositDataRoot The SHA-256 hash of the SSZ-encoded DepositData object.
    /// @param exitDate The expected exit date of the created validator
    function createValidator(
        bytes calldata validatorPubKey, // 48 bytes
        bytes calldata depositSignature, // 96 bytes
        bytes32 depositDataRoot,
        uint64 exitDate
    ) external;

    /// @notice Deposits `msg.value` of ETH.
    /// @dev If the balance of the contract exceeds 32 ETH, the excess will be sent
    /// back to `msg.sender`.
    /// Emits a {Deposit} event.
    function deposit() external payable returns (uint256 surplus);


    /// @notice Deposits `msg.value` of ETH on behalf of `depositor`.
    /// @dev If the balance of the contract exceeds 32 ETH, the excess will be sent
    /// back to `depositor`.
    /// Emits a {Deposit} event.
    function depositOnBehalfOf(address depositor) external payable returns (uint256 surplus);

    /// @notice Settles operator service commission and enable withdrawal.
    /// @dev It can be called by operator if the time has passed `_exitDate`.
    /// It can be called by any address if the time has passed `_exitDate + MAX_SECONDS_IN_EXIT_QUEUE`.
    /// Emits a {ServiceEnd} event.
    function endOperatorServices() external;

    /// @notice Withdraws all the ETH of `msg.sender`.
    /// @dev It can only be called when the contract state is not `PostDeposit`.
    /// Emits a {Withdrawal} event.
    /// @param minimumETHAmount The minimum amount of ETH that must be received for the transaction not to revert.
    function withdrawAll(uint256 minimumETHAmount) external returns (uint256);

    /// @notice Withdraws the ETH of `msg.sender` which is corresponding to the `amount` of deposit stake.
    /// @dev It can only be called when the contract state is not `PostDeposit`.
    /// Emits a {Withdrawal} event.
    /// @param amount The amount of deposit stake to be converted to ETH.
    /// @param minimumETHAmount The minimum amount of ETH that must be received for the transaction not to revert.
    function withdraw(uint256 amount, uint256 minimumETHAmount) external returns (uint256);

    /// @notice Withdraws the ETH of `msg.sender` which is corresponding to the `amount` of deposit stake to a specified address.
    /// @dev It can only be called when the contract state is not `PostDeposit`.
    /// Emits a {Withdrawal} event.
    /// @param amount The amount of deposit stake to be converted to ETH.
    /// @param beneficiary The address of ETH receiver.
    /// @param minimumETHAmount The minimum amount of ETH that must be received for the transaction not to revert.
    function withdrawTo(
        uint256 amount,
        address payable beneficiary,
        uint256 minimumETHAmount
    ) external returns (uint256);

    /// @notice Sets `amount` as the allowance of `spender` over the caller's deposit stake.
    /// @dev Emits an {Approval} event.
    function approve(address spender, uint256 amount) external returns (bool);

    /// @notice Increases the allowance granted to `spender` by the caller.
    /// @dev Emits an {Approval} event indicating the upated allowances;
    function increaseAllowance(address spender, uint256 addValue) external returns (bool);

    /// @notice Decreases the allowance granted to `spender` by the caller.
    /// @dev Emits an {Approval} event indicating the upated allowances;
    /// It reverts if current allowance is less than `subtractedValue`.
    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /// @notice Decreases the allowance granted to `spender` by the caller.
    /// @dev Emits an {Approval} event indicating the upated allowances;
    /// It sets allowance to zero if current allowance is less than `subtractedValue`.
    function forceDecreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /// @notice Sets `amount` as the allowance of `spender` over the caller's deposit amount that can be withdrawn.
    /// @dev Emits an {WithdrawalApproval} event.
    function approveWithdrawal(address spender, uint256 amount) external returns (bool);

    /// @notice Increases the allowance of withdrawal granted to `spender` by the caller.
    /// @dev Emits an {WithdrawalApproval} event indicating the upated allowances;
    function increaseWithdrawalAllowance(address spender, uint256 addValue) external returns (bool);

    /// @notice Decreases the allowance of withdrawal granted to `spender` by the caller.
    /// @dev Emits an {WithdrawwalApproval} event indicating the upated allowances;
    /// It reverts if current allowance is less than `subtractedValue`.
    function decreaseWithdrawalAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /// @notice Decreases the allowance of withdrawal granted to `spender` by the caller.
    /// @dev Emits an {WithdrawwalApproval} event indicating the upated allowances;
    /// It reverts if current allowance is less than `subtractedValue`.
    function forceDecreaseWithdrawalAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /// @notice Withdraws the ETH of `depositor` which is corresponding to the `amount` of deposit stake to a specified address.
    /// @dev Emits a {Withdrawal} event.
    /// Emits a {WithdrawalApproval} event indicating the updated allowance.
    /// @param depositor The address of deposit stake holder.
    /// @param beneficiary The address of ETH receiver.
    /// @param amount The amount of deposit stake to be converted to ETH.
    /// @param minimumETHAmount The minimum amount of ETH that must be received for the transaction not to revert.
    function withdrawFrom(
        address depositor,
        address payable beneficiary,
        uint256 amount,
        uint256 minimumETHAmount
    ) external returns (uint256);

    /// @notice Transfers `amount` deposit stake from caller to `to`.
    /// @dev Emits a {Transfer} event.
    function transferDeposit(address to, uint256 amount) external returns (bool);

    /// @notice Transfers `amount` deposit stake from `from` to `to`.
    /// @dev Emits a {Transfer} event.
    /// Emits an {Approval} event indicating the updated allowance.
    function transferDepositFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);

    /// @notice Transfers operator claimable commission fee to the operator address.
    /// @dev Emits a {Claim} event.
    function operatorClaim() external returns (uint256);

    /// @notice Returns the remaining number of deposit stake that `spender` will be allowed to withdraw
    /// on behalf of `depositor` through {withdrawFrom}.
    function withdrawalAllowance(address depositor, address spender) external view returns (uint256);

    /// @notice Returns the operator service commission rate.
    function getCommissionRate() external view returns (uint256);

    /// @notice Returns operator claimable commission fee.
    function getOperatorClaimable() external view returns (uint256);

    /// @notice Returns the exit date of the validator.
    function getExitDate() external view returns (uint256);

    /// @notice Returns the state of the contract.
    function getState() external view returns (State);

    /// @notice Returns the address of operator.
    function getOperatorAddress() external view returns (address);

    /// @notice Returns the amount of deposit stake owned by `depositor`.
    function getDeposit(address depositor) external view returns (uint256);

    /// @notice Returns the total amount of deposit stake.
    function getTotalDeposits() external view returns (uint256);

    /// @notice Returns the remaining number of deposit stake that `spender` will be allowed to transfer
    /// on behalf of `depositor` through {transferDepositFrom}.
    function getAllowance(address owner, address spender) external view returns (uint256);

    /// @notice Returns the commitment which is the hash of the contract address and all inputs to the `createValidator` function.
    function getOperatorDataCommitment() external view returns (bytes32);

    /// @notice Returns the amount of ETH that is withdrawable by `owner`.
    function getWithdrawableAmount(address owner) external view returns (uint256);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4d0f8c1da8654a478f046ea7cf83d2166e1025af/contracts/utils/Address.sol

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"ServiceEnd","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"pubkey","type":"bytes"}],"name":"ValidatorDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawalApproval","type":"event"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approveWithdrawal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"validatorPubKey","type":"bytes"},{"internalType":"bytes","name":"depositSignature","type":"bytes"},{"internalType":"bytes32","name":"depositDataRoot","type":"bytes32"},{"internalType":"uint64","name":"exitDate","type":"uint64"}],"name":"createValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseWithdrawalAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[{"internalType":"uint256","name":"surplus","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"depositContract","outputs":[{"internalType":"contract IDepositContract","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"}],"name":"depositOnBehalfOf","outputs":[{"internalType":"uint256","name":"surplus","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"endOperatorServices","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"forceDecreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"forceDecreaseWithdrawalAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"getAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCommissionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"}],"name":"getDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExitDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOperatorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOperatorClaimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOperatorDataCommitment","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getState","outputs":[{"internalType":"enum IStakefishServicesContract.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"getWithdrawableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseWithdrawalAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"commissionRate","type":"uint24"},{"internalType":"address","name":"operatorAddress","type":"address"},{"internalType":"bytes32","name":"operatorDataCommitment","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operatorClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferDeposit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferDepositFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"newExitDate","type":"uint64"}],"name":"updateExitDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minimumETHAmount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minimumETHAmount","type":"uint256"}],"name":"withdrawAll","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"minimumETHAmount","type":"uint256"}],"name":"withdrawFrom","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"minimumETHAmount","type":"uint256"}],"name":"withdrawTo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"depositor","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"withdrawalAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

608060405234801561001057600080fd5b50612bfa806100206000396000f3fe6080604052600436106102025760003560e01c8063671a24f11161011d578063cfe2edcb116100b0578063e94ad65b1161007f578063f54c071411610064578063f54c071414610767578063f632c1af14610787578063f67771751461079c57600080fd5b8063e94ad65b14610723578063f4970e711461074757600080fd5b8063cfe2edcb146106a5578063d0e30db0146106b8578063d4fdc309146106c0578063e1254fba146106e057600080fd5b8063924d2784116100ec578063924d27841461060b578063958e2d3114610645578063a457c2d714610665578063caa7262b1461068557600080fd5b8063671a24f1146105a15780636a8d8d8d146105b65780636ce858bf146105d65780637fcd7332146105f657600080fd5b8063395093511161019557806350f3dbec1161016457806350f3dbec146104ee5780635d13d5141461050e5780635d722feb1461052e578063666c10351461058157600080fd5b806339509351146104745780633e4eb36c14610494578063441a3e70146104ae57806346fcb042146104ce57600080fd5b8063171808af116101d1578063171808af146103a95780631865c57d146103c95780631ca800971461040c5780632ec338ba1461042157600080fd5b8063095ea7b3146102de5780630af4187d146103135780630e2cc32714610374578063168a48221461039457600080fd5b366102d95760016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff16600381111561026a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14156102d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f506c61696e204574686572207472616e73666572206e6f7420616c6c6f77656460448201526064015b60405180910390fd5b005b600080fd5b3480156102ea57600080fd5b506102fe6102f936600461276c565b6107bc565b60405190151581526020015b60405180910390f35b34801561031f57600080fd5b5061036661032e3660046126af565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020908152604080832093909416825291909152205490565b60405190815260200161030a565b34801561038057600080fd5b506102fe61038f36600461276c565b6107d2565b3480156103a057600080fd5b50600554610366565b3480156103b557600080fd5b506102fe6103c436600461276c565b61081b565b3480156103d557600080fd5b506000547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660405161030a9190612a53565b34801561041857600080fd5b50600154610366565b34801561042d57600080fd5b506000546301000000900473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161030a565b34801561048057600080fd5b506102fe61048f36600461276c565b610876565b3480156104a057600080fd5b5060005462ffffff16610366565b3480156104ba57600080fd5b506103666104c9366004612880565b6108ba565b3480156104da57600080fd5b506102fe6104e936600461276c565b6109f3565b3480156104fa57600080fd5b506102fe61050936600461276c565b610a3f565b34801561051a57600080fd5b506102d7610529366004612797565b610a4c565b34801561053a57600080fd5b506103666105493660046126af565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260036020908152604080832093909416825291909152205490565b34801561058d57600080fd5b506102fe61059c36600461276c565b610ec9565b3480156105ad57600080fd5b50600654610366565b3480156105c257600080fd5b506102d76105d13660046128a1565b610f0d565b3480156105e257600080fd5b506102d76105f136600461281c565b61116f565b34801561060257600080fd5b506102d7611350565b34801561061757600080fd5b5060005477010000000000000000000000000000000000000000000000900467ffffffffffffffff16610366565b34801561065157600080fd5b50610366610660366004612842565b611691565b34801561067157600080fd5b506102fe61068036600461276c565b6117d9565b34801561069157600080fd5b506103666106a036600461285a565b61181d565b6103666106b3366004612693565b611957565b610366611a2c565b3480156106cc57600080fd5b506103666106db3660046126e7565b611b06565b3480156106ec57600080fd5b506103666106fb366004612693565b73ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b34801561072f57600080fd5b5061044f6f219ab540356cbb839cbe05303d7705fa81565b34801561075357600080fd5b506102fe61076236600461276c565b611ce9565b34801561077357600080fd5b506102fe61078236600461272c565b611cf6565b34801561079357600080fd5b50610366611d4e565b3480156107a857600080fd5b506103666107b7366004612693565b611e6d565b60006107c9338484611f2a565b50600192915050565b33600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610816908690612aa7565b612016565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161086c908561085d86856120f9565b6108679085612b35565b611f2a565b5060019392505050565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610867908690612aa7565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff16600381111561091f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba16024913990610972576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b50600061098033338661210f565b9050828110156109ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b9392505050565b33600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161086c9085610a3586856120f9565b6108169085612b35565b60006107c933848461226f565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865206f70657261746f7200000000000060448201526064016102ce565b60016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115610b37577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610b9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f56616c696461746f7220686173206265656e206372656174656400000000000060448201526064016102ce565b600080547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f020000000000000000000000000000000000000000000000000000000000000017905560308514610c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f496e76616c69642076616c696461746f72207075626c6963206b65790000000060448201526064016102ce565b60608314610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f496e76616c6964206465706f736974207369676e61747572650000000000000060448201526064016102ce565b30868686868686604051602001610cd8979695949392919061296e565b6040516020818303038152906040528051906020012060015414610d58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4461746120646f65736e2774206d6174636820636f6d6d69746d656e7400000060448201526064016102ce565b600080547fff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000067ffffffffffffffff841602179055604080517f010000000000000000000000000000000000000000000000000000000000000060208201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b16602c8201526f219ab540356cbb839cbe05303d7705fa916322895118916801bc16d674ec800000918a918a91016040516020818303038152906040528989896040518863ffffffff1660e01b8152600401610e5696959493929190612a04565b6000604051808303818588803b158015610e6f57600080fd5b505af1158015610e83573d6000803e3d6000fd5b50505050507fc7114975f4ef557d4d63c6e4171d351eb22178fecbeefc10214791527c1df0c58686604051610eb99291906129f0565b60405180910390a1505050505050565b33600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610816908690612b35565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610f95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865206f70657261746f7200000000000060448201526064016102ce565b60026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115610ff8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1461105f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f56616c696461746f72206973206e6f742061637469766500000000000000000060448201526064016102ce565b60005467ffffffffffffffff77010000000000000000000000000000000000000000000000909104811690821610611119576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f4e6f74206561726c696572207468616e20746865206f726967696e616c20766160448201527f6c7565000000000000000000000000000000000000000000000000000000000060648201526084016102ce565b6000805467ffffffffffffffff90921677010000000000000000000000000000000000000000000000027fff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b600080547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660038111156111d1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611238576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f436f6e747261637420697320616c726561647920696e697469616c697a65640060448201526064016102ce565b600080547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0100000000000000000000000000000000000000000000000000000000000000179055620f424062ffffff841611156112f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f436f6d6d697373696f6e20726174652065786365656473207363616c6500000060448201526064016102ce565b6000805473ffffffffffffffffffffffffffffffffffffffff9093166301000000027fffffffffffffffffff000000000000000000000000000000000000000000000090931662ffffff9094169390931791909117909155600155565b47806113b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e277420656e64207769746820302062616c616e6365000000000000000060448201526064016102ce565b60026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff16600381111561141b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4e6f7420616c6c6f77656420696e207468652063757272656e7420737461746560448201526064016102ce565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff16331480156114d6575060005477010000000000000000000000000000000000000000000000900467ffffffffffffffff1642115b8061154e5750336000908152600460205260409020541580159061154e5750611502610e106018612af8565b61150e9061016d612af8565b611519906001612af8565b60005461154b919077010000000000000000000000000000000000000000000000900467ffffffffffffffff16612aa7565b42115b6115b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4e6f7420616c6c6f776564206174207468652063757272656e742074696d650060448201526064016102ce565b600080547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f03000000000000000000000000000000000000000000000000000000000000001790556801bc16d674ec8000008111156116655760006116236801bc16d674ec80000083612b35565b6000805491925090620f42409061163f9062ffffff1684612af8565b6116499190612abf565b9050806006600082825461165d9190612aa7565b909155505050505b6040517ffbd6622fc13ddf86275d242b7ed2c826cd2a9bc82b2c6db61a651c8b044339f690600090a150565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660038111156116f6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba16024913990611749576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b5033600081815260046020526040812054909161176791819061210f565b9050828110156117d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b92915050565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610867908690612b35565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611882577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba160249139906118d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b5060006118e333858761210f565b90508281101561194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b949350505050565b600060016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660038111156119bc577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611a23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f56616c696461746f7220616c726561647920637265617465640000000000000060448201526064016102ce565b6117d3826123c1565b600060016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611a91577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611af8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f56616c696461746f7220616c726561647920637265617465640000000000000060448201526064016102ce565b611b01336123c1565b905090565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611b6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba16024913990611bbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b5073ffffffffffffffffffffffffffffffffffffffff8516600090815260036020908152604080832033845290915281205490611bfb8583612b35565b73ffffffffffffffffffffffffffffffffffffffff8816600081815260036020908152604080832033808552908352928190208590555184815293945090927f86cf336bf0eef9691e91aad1f012fdff22e082219d77b1b84289e919a1ed1326910160405180910390a36000611c7288888861210f565b905084811015611cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b979650505050505050565b60006107c9338484612016565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152604080832033808552925282205490611d389086906108678685612b35565b611d4385858561226f565b506001949350505050565b600080546301000000900473ffffffffffffffffffffffffffffffffffffffff163314611dd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865206f70657261746f7200000000000060448201526064016102ce565b6006548015611b01576000600681905554611e0f906301000000900473ffffffffffffffffffffffffffffffffffffffff16826124d0565b60005460408051630100000090920473ffffffffffffffffffffffffffffffffffffffff168252602082018390527f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4910160405180910390a1905090565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611ed2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415611ee057506000919050565b600554600654611ef09047612b35565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260046020526040902054611f209190612af8565b6117d39190612abf565b73ffffffffffffffffffffffffffffffffffffffff8216611fa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f417070726f766520746f20746865207a65726f2061646472657373000000000060448201526064016102ce565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8216612093576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f417070726f766520746f20746865207a65726f2061646472657373000000000060448201526064016102ce565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526003602090815260408083209487168084529482529182902085905590518481527f86cf336bf0eef9691e91aad1f012fdff22e082219d77b1b84289e919a1ed13269101612009565b600081831061210857816109ec565b5090919050565b600080821161217a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f416d6f756e742073686f756c646e2774206265207a65726f000000000000000060448201526064016102ce565b60006005546006544761218d9190612b35565b6121979085612af8565b6121a19190612abf565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600460205260408120805492935085929091906121db908490612b35565b9250508190555082600560008282546121f49190612b35565b9091555050604080518481526020810183905273ffffffffffffffffffffffffffffffffffffffff80871692908816917fc2b4a290c20fb28939d29f102514fbffd2b73c059ffba8b78250c94161d5fcc6910160405180910390a361194f73ffffffffffffffffffffffffffffffffffffffff8516826124d0565b73ffffffffffffffffffffffffffffffffffffffff82166122ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f5472616e7366657220746f20746865207a65726f20616464726573730000000060448201526064016102ce565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602052604081208054839290612321908490612b35565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152600460205260408120805483929061235b908490612aa7565b925050819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161200991815260200190565b6000346801bc16d674ec80000047116123db5760006123ee565b6123ee6801bc16d674ec80000047612b35565b915060006123fc8383612b35565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020526040812080549293508392909190612436908490612aa7565b92505081905550806005600082825461244f9190612aa7565b90915550506040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c910160405180910390a182156124c9576124c973ffffffffffffffffffffffffffffffffffffffff8516846124d0565b5050919050565b8047101561253a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016102ce565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612594576040519150601f19603f3d011682016040523d82523d6000602084013e612599565b606091505b505090508061262a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016102ce565b505050565b60008083601f840112612640578182fd5b50813567ffffffffffffffff811115612657578182fd5b60208301915083602082850101111561266f57600080fd5b9250929050565b803567ffffffffffffffff8116811461268e57600080fd5b919050565b6000602082840312156126a4578081fd5b81356109ec81612b7b565b600080604083850312156126c1578081fd5b82356126cc81612b7b565b915060208301356126dc81612b7b565b809150509250929050565b600080600080608085870312156126fc578182fd5b843561270781612b7b565b9350602085013561271781612b7b565b93969395505050506040820135916060013590565b600080600060608486031215612740578283fd5b833561274b81612b7b565b9250602084013561275b81612b7b565b929592945050506040919091013590565b6000806040838503121561277e578182fd5b823561278981612b7b565b946020939093013593505050565b600080600080600080608087890312156127af578182fd5b863567ffffffffffffffff808211156127c6578384fd5b6127d28a838b0161262f565b909850965060208901359150808211156127ea578384fd5b506127f789828a0161262f565b9095509350506040870135915061281060608801612676565b90509295509295509295565b600080600060608486031215612830578283fd5b833562ffffff8116811461274b578384fd5b600060208284031215612853578081fd5b5035919050565b60008060006060848603121561286e578283fd5b83359250602084013561275b81612b7b565b60008060408385031215612892578182fd5b50508035926020909101359150565b6000602082840312156128b2578081fd5b6109ec82612676565b81835281816020850137506000806020838501015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600081518084526020825b8281101561292957848101820151868201830152810161290e565b8281111561293957838284880101525b50807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401168601019250505092915050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008860601b16815285876014830137600086820160148101828152868882375060149501948501939093525060c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016603483015250603c01949350505050565b60208152600061194f6020830184866128bb565b608081526000612a1860808301888a6128bb565b8281036020840152612a2a8188612903565b90508281036040840152612a3f8186886128bb565b915050826060830152979650505050505050565b6020810160048310612a8e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6020815260006109ec6020830184612903565b60008219821115612aba57612aba612b4c565b500190565b600082612af3577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612b3057612b30612b4c565b500290565b600082821015612b4757612b47612b4c565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff81168114612b9d57600080fd5b5056fe4e6f7420616c6c6f776564207768656e2076616c696461746f7220697320616374697665a26469706673582212200b7cedc9067ec1d24c831fc4b3489f87a6a061209f64b8e65feac3fd71122a1764736f6c63430008040033

Deployed Bytecode

0x6080604052600436106102025760003560e01c8063671a24f11161011d578063cfe2edcb116100b0578063e94ad65b1161007f578063f54c071411610064578063f54c071414610767578063f632c1af14610787578063f67771751461079c57600080fd5b8063e94ad65b14610723578063f4970e711461074757600080fd5b8063cfe2edcb146106a5578063d0e30db0146106b8578063d4fdc309146106c0578063e1254fba146106e057600080fd5b8063924d2784116100ec578063924d27841461060b578063958e2d3114610645578063a457c2d714610665578063caa7262b1461068557600080fd5b8063671a24f1146105a15780636a8d8d8d146105b65780636ce858bf146105d65780637fcd7332146105f657600080fd5b8063395093511161019557806350f3dbec1161016457806350f3dbec146104ee5780635d13d5141461050e5780635d722feb1461052e578063666c10351461058157600080fd5b806339509351146104745780633e4eb36c14610494578063441a3e70146104ae57806346fcb042146104ce57600080fd5b8063171808af116101d1578063171808af146103a95780631865c57d146103c95780631ca800971461040c5780632ec338ba1461042157600080fd5b8063095ea7b3146102de5780630af4187d146103135780630e2cc32714610374578063168a48221461039457600080fd5b366102d95760016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff16600381111561026a577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14156102d7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f506c61696e204574686572207472616e73666572206e6f7420616c6c6f77656460448201526064015b60405180910390fd5b005b600080fd5b3480156102ea57600080fd5b506102fe6102f936600461276c565b6107bc565b60405190151581526020015b60405180910390f35b34801561031f57600080fd5b5061036661032e3660046126af565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260026020908152604080832093909416825291909152205490565b60405190815260200161030a565b34801561038057600080fd5b506102fe61038f36600461276c565b6107d2565b3480156103a057600080fd5b50600554610366565b3480156103b557600080fd5b506102fe6103c436600461276c565b61081b565b3480156103d557600080fd5b506000547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660405161030a9190612a53565b34801561041857600080fd5b50600154610366565b34801561042d57600080fd5b506000546301000000900473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161030a565b34801561048057600080fd5b506102fe61048f36600461276c565b610876565b3480156104a057600080fd5b5060005462ffffff16610366565b3480156104ba57600080fd5b506103666104c9366004612880565b6108ba565b3480156104da57600080fd5b506102fe6104e936600461276c565b6109f3565b3480156104fa57600080fd5b506102fe61050936600461276c565b610a3f565b34801561051a57600080fd5b506102d7610529366004612797565b610a4c565b34801561053a57600080fd5b506103666105493660046126af565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260036020908152604080832093909416825291909152205490565b34801561058d57600080fd5b506102fe61059c36600461276c565b610ec9565b3480156105ad57600080fd5b50600654610366565b3480156105c257600080fd5b506102d76105d13660046128a1565b610f0d565b3480156105e257600080fd5b506102d76105f136600461281c565b61116f565b34801561060257600080fd5b506102d7611350565b34801561061757600080fd5b5060005477010000000000000000000000000000000000000000000000900467ffffffffffffffff16610366565b34801561065157600080fd5b50610366610660366004612842565b611691565b34801561067157600080fd5b506102fe61068036600461276c565b6117d9565b34801561069157600080fd5b506103666106a036600461285a565b61181d565b6103666106b3366004612693565b611957565b610366611a2c565b3480156106cc57600080fd5b506103666106db3660046126e7565b611b06565b3480156106ec57600080fd5b506103666106fb366004612693565b73ffffffffffffffffffffffffffffffffffffffff1660009081526004602052604090205490565b34801561072f57600080fd5b5061044f6f219ab540356cbb839cbe05303d7705fa81565b34801561075357600080fd5b506102fe61076236600461276c565b611ce9565b34801561077357600080fd5b506102fe61078236600461272c565b611cf6565b34801561079357600080fd5b50610366611d4e565b3480156107a857600080fd5b506103666107b7366004612693565b611e6d565b60006107c9338484611f2a565b50600192915050565b33600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610816908690612aa7565b612016565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161086c908561085d86856120f9565b6108679085612b35565b611f2a565b5060019392505050565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610867908690612aa7565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff16600381111561091f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba16024913990610972576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b50600061098033338661210f565b9050828110156109ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b9392505050565b33600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152812054909161086c9085610a3586856120f9565b6108169085612b35565b60006107c933848461226f565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610ad4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865206f70657261746f7200000000000060448201526064016102ce565b60016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115610b37577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14610b9e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f56616c696461746f7220686173206265656e206372656174656400000000000060448201526064016102ce565b600080547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f020000000000000000000000000000000000000000000000000000000000000017905560308514610c51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f496e76616c69642076616c696461746f72207075626c6963206b65790000000060448201526064016102ce565b60608314610cbb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f496e76616c6964206465706f736974207369676e61747572650000000000000060448201526064016102ce565b30868686868686604051602001610cd8979695949392919061296e565b6040516020818303038152906040528051906020012060015414610d58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f4461746120646f65736e2774206d6174636820636f6d6d69746d656e7400000060448201526064016102ce565b600080547fff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff167701000000000000000000000000000000000000000000000067ffffffffffffffff841602179055604080517f010000000000000000000000000000000000000000000000000000000000000060208201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003060601b16602c8201526f219ab540356cbb839cbe05303d7705fa916322895118916801bc16d674ec800000918a918a91016040516020818303038152906040528989896040518863ffffffff1660e01b8152600401610e5696959493929190612a04565b6000604051808303818588803b158015610e6f57600080fd5b505af1158015610e83573d6000803e3d6000fd5b50505050507fc7114975f4ef557d4d63c6e4171d351eb22178fecbeefc10214791527c1df0c58686604051610eb99291906129f0565b60405180910390a1505050505050565b33600081815260036020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610816908690612b35565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff163314610f95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865206f70657261746f7200000000000060448201526064016102ce565b60026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115610ff8577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1461105f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f56616c696461746f72206973206e6f742061637469766500000000000000000060448201526064016102ce565b60005467ffffffffffffffff77010000000000000000000000000000000000000000000000909104811690821610611119576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f4e6f74206561726c696572207468616e20746865206f726967696e616c20766160448201527f6c7565000000000000000000000000000000000000000000000000000000000060648201526084016102ce565b6000805467ffffffffffffffff90921677010000000000000000000000000000000000000000000000027fff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff909216919091179055565b600080547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660038111156111d1577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611238576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f436f6e747261637420697320616c726561647920696e697469616c697a65640060448201526064016102ce565b600080547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0100000000000000000000000000000000000000000000000000000000000000179055620f424062ffffff841611156112f3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f436f6d6d697373696f6e20726174652065786365656473207363616c6500000060448201526064016102ce565b6000805473ffffffffffffffffffffffffffffffffffffffff9093166301000000027fffffffffffffffffff000000000000000000000000000000000000000000000090931662ffffff9094169390931791909117909155600155565b47806113b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f43616e277420656e64207769746820302062616c616e6365000000000000000060448201526064016102ce565b60026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff16600381111561141b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611482576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4e6f7420616c6c6f77656420696e207468652063757272656e7420737461746560448201526064016102ce565b6000546301000000900473ffffffffffffffffffffffffffffffffffffffff16331480156114d6575060005477010000000000000000000000000000000000000000000000900467ffffffffffffffff1642115b8061154e5750336000908152600460205260409020541580159061154e5750611502610e106018612af8565b61150e9061016d612af8565b611519906001612af8565b60005461154b919077010000000000000000000000000000000000000000000000900467ffffffffffffffff16612aa7565b42115b6115b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f4e6f7420616c6c6f776564206174207468652063757272656e742074696d650060448201526064016102ce565b600080547effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f03000000000000000000000000000000000000000000000000000000000000001790556801bc16d674ec8000008111156116655760006116236801bc16d674ec80000083612b35565b6000805491925090620f42409061163f9062ffffff1684612af8565b6116499190612abf565b9050806006600082825461165d9190612aa7565b909155505050505b6040517ffbd6622fc13ddf86275d242b7ed2c826cd2a9bc82b2c6db61a651c8b044339f690600090a150565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660038111156116f6577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba16024913990611749576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b5033600081815260046020526040812054909161176791819061210f565b9050828110156117d3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b92915050565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490916107c9918590610867908690612b35565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611882577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba160249139906118d5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b5060006118e333858761210f565b90508281101561194f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b949350505050565b600060016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff1660038111156119bc577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611a23576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f56616c696461746f7220616c726561647920637265617465640000000000000060448201526064016102ce565b6117d3826123c1565b600060016000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611a91577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b14611af8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f56616c696461746f7220616c726561647920637265617465640000000000000060448201526064016102ce565b611b01336123c1565b905090565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611b6b577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415604051806060016040528060248152602001612ba16024913990611bbe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102ce9190612a94565b5073ffffffffffffffffffffffffffffffffffffffff8516600090815260036020908152604080832033845290915281205490611bfb8583612b35565b73ffffffffffffffffffffffffffffffffffffffff8816600081815260036020908152604080832033808552908352928190208590555184815293945090927f86cf336bf0eef9691e91aad1f012fdff22e082219d77b1b84289e919a1ed1326910160405180910390a36000611c7288888861210f565b905084811015611cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f4c657373207468616e206d696e696d756d20616d6f756e74000000000000000060448201526064016102ce565b979650505050505050565b60006107c9338484612016565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260026020908152604080832033808552925282205490611d389086906108678685612b35565b611d4385858561226f565b506001949350505050565b600080546301000000900473ffffffffffffffffffffffffffffffffffffffff163314611dd7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f43616c6c6572206973206e6f7420746865206f70657261746f7200000000000060448201526064016102ce565b6006548015611b01576000600681905554611e0f906301000000900473ffffffffffffffffffffffffffffffffffffffff16826124d0565b60005460408051630100000090920473ffffffffffffffffffffffffffffffffffffffff168252602082018390527f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4910160405180910390a1905090565b600060026000547f0100000000000000000000000000000000000000000000000000000000000000900460ff166003811115611ed2577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b1415611ee057506000919050565b600554600654611ef09047612b35565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260046020526040902054611f209190612af8565b6117d39190612abf565b73ffffffffffffffffffffffffffffffffffffffff8216611fa7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f417070726f766520746f20746865207a65726f2061646472657373000000000060448201526064016102ce565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b73ffffffffffffffffffffffffffffffffffffffff8216612093576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f417070726f766520746f20746865207a65726f2061646472657373000000000060448201526064016102ce565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526003602090815260408083209487168084529482529182902085905590518481527f86cf336bf0eef9691e91aad1f012fdff22e082219d77b1b84289e919a1ed13269101612009565b600081831061210857816109ec565b5090919050565b600080821161217a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f416d6f756e742073686f756c646e2774206265207a65726f000000000000000060448201526064016102ce565b60006005546006544761218d9190612b35565b6121979085612af8565b6121a19190612abf565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600460205260408120805492935085929091906121db908490612b35565b9250508190555082600560008282546121f49190612b35565b9091555050604080518481526020810183905273ffffffffffffffffffffffffffffffffffffffff80871692908816917fc2b4a290c20fb28939d29f102514fbffd2b73c059ffba8b78250c94161d5fcc6910160405180910390a361194f73ffffffffffffffffffffffffffffffffffffffff8516826124d0565b73ffffffffffffffffffffffffffffffffffffffff82166122ec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f5472616e7366657220746f20746865207a65726f20616464726573730000000060448201526064016102ce565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602052604081208054839290612321908490612b35565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000908152600460205260408120805483929061235b908490612aa7565b925050819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161200991815260200190565b6000346801bc16d674ec80000047116123db5760006123ee565b6123ee6801bc16d674ec80000047612b35565b915060006123fc8383612b35565b73ffffffffffffffffffffffffffffffffffffffff8516600090815260046020526040812080549293508392909190612436908490612aa7565b92505081905550806005600082825461244f9190612aa7565b90915550506040805173ffffffffffffffffffffffffffffffffffffffff86168152602081018390527fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c910160405180910390a182156124c9576124c973ffffffffffffffffffffffffffffffffffffffff8516846124d0565b5050919050565b8047101561253a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016102ce565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114612594576040519150601f19603f3d011682016040523d82523d6000602084013e612599565b606091505b505090508061262a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016102ce565b505050565b60008083601f840112612640578182fd5b50813567ffffffffffffffff811115612657578182fd5b60208301915083602082850101111561266f57600080fd5b9250929050565b803567ffffffffffffffff8116811461268e57600080fd5b919050565b6000602082840312156126a4578081fd5b81356109ec81612b7b565b600080604083850312156126c1578081fd5b82356126cc81612b7b565b915060208301356126dc81612b7b565b809150509250929050565b600080600080608085870312156126fc578182fd5b843561270781612b7b565b9350602085013561271781612b7b565b93969395505050506040820135916060013590565b600080600060608486031215612740578283fd5b833561274b81612b7b565b9250602084013561275b81612b7b565b929592945050506040919091013590565b6000806040838503121561277e578182fd5b823561278981612b7b565b946020939093013593505050565b600080600080600080608087890312156127af578182fd5b863567ffffffffffffffff808211156127c6578384fd5b6127d28a838b0161262f565b909850965060208901359150808211156127ea578384fd5b506127f789828a0161262f565b9095509350506040870135915061281060608801612676565b90509295509295509295565b600080600060608486031215612830578283fd5b833562ffffff8116811461274b578384fd5b600060208284031215612853578081fd5b5035919050565b60008060006060848603121561286e578283fd5b83359250602084013561275b81612b7b565b60008060408385031215612892578182fd5b50508035926020909101359150565b6000602082840312156128b2578081fd5b6109ec82612676565b81835281816020850137506000806020838501015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b600081518084526020825b8281101561292957848101820151868201830152810161290e565b8281111561293957838284880101525b50807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401168601019250505092915050565b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008860601b16815285876014830137600086820160148101828152868882375060149501948501939093525060c01b7fffffffffffffffff00000000000000000000000000000000000000000000000016603483015250603c01949350505050565b60208152600061194f6020830184866128bb565b608081526000612a1860808301888a6128bb565b8281036020840152612a2a8188612903565b90508281036040840152612a3f8186886128bb565b915050826060830152979650505050505050565b6020810160048310612a8e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6020815260006109ec6020830184612903565b60008219821115612aba57612aba612b4c565b500190565b600082612af3577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612b3057612b30612b4c565b500290565b600082821015612b4757612b47612b4c565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff81168114612b9d57600080fd5b5056fe4e6f7420616c6c6f776564207768656e2076616c696461746f7220697320616374697665a26469706673582212200b7cedc9067ec1d24c831fc4b3489f87a6a061209f64b8e65feac3fd71122a1764736f6c63430008040033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
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.