ETH Price: $3,151.79 (-5.68%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
GuardianLib

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion
File 1 of 10 : GuardianLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "./WalletData.sol";
import "./ApprovalLib.sol";
import "../../lib/SignatureUtil.sol";
import "../../thirdparty/SafeCast.sol";


/// @title GuardianModule
/// @author Brecht Devos - <[email protected]>
/// @author Daniel Wang - <[email protected]>
library GuardianLib
{
    using AddressUtil   for address;
    using SafeCast      for uint;
    using SignatureUtil for bytes32;
    using ApprovalLib   for Wallet;

    uint public constant MAX_GUARDIANS           = 10;
    uint public constant GUARDIAN_PENDING_PERIOD = 3 days;

    bytes32 public constant ADD_GUARDIAN_TYPEHASH = keccak256(
        "addGuardian(address wallet,uint256 validUntil,address guardian)"
    );
    bytes32 public constant REMOVE_GUARDIAN_TYPEHASH = keccak256(
        "removeGuardian(address wallet,uint256 validUntil,address guardian)"
    );
    bytes32 public constant RESET_GUARDIANS_TYPEHASH = keccak256(
        "resetGuardians(address wallet,uint256 validUntil,address[] guardians)"
    );

    event GuardianAdded   (address guardian, uint effectiveTime);
    event GuardianRemoved (address guardian, uint effectiveTime);

    function addGuardiansImmediately(
        Wallet    storage wallet,
        address[] memory  _guardians
        )
        external
    {
        address guardian = address(0);
        for (uint i = 0; i < _guardians.length; i++) {
            require(_guardians[i] > guardian, "INVALID_ORDERING");
            guardian = _guardians[i];
            _addGuardian(wallet, guardian, 0, true);
        }
    }

    function addGuardian(
        Wallet storage wallet,
        address guardian
        )
        external
    {
        _addGuardian(wallet, guardian, GUARDIAN_PENDING_PERIOD, false);
    }

    function addGuardianWA(
        Wallet   storage  wallet,
        bytes32           domainSeparator,
        Approval calldata approval,
        address  guardian
        )
        external
        returns (bytes32 approvedHash)
    {
        approvedHash = wallet.verifyApproval(
            domainSeparator,
            SigRequirement.MAJORITY_OWNER_REQUIRED,
            approval,
            abi.encode(
                ADD_GUARDIAN_TYPEHASH,
                approval.wallet,
                approval.validUntil,
                guardian
            )
        );

        _addGuardian(wallet, guardian, 0, true);
    }

    function removeGuardian(
        Wallet storage wallet,
        address guardian
        )
        external
    {
        _removeGuardian(wallet, guardian, GUARDIAN_PENDING_PERIOD, false);
    }

    function removeGuardianWA(
        Wallet   storage  wallet,
        bytes32           domainSeparator,
        Approval calldata approval,
        address  guardian
        )
        external
        returns (bytes32 approvedHash)
    {
        approvedHash = wallet.verifyApproval(
            domainSeparator,
            SigRequirement.MAJORITY_OWNER_REQUIRED,
            approval,
            abi.encode(
                REMOVE_GUARDIAN_TYPEHASH,
                approval.wallet,
                approval.validUntil,
                guardian
            )
        );

        _removeGuardian(wallet, guardian, 0, true);
    }

    function resetGuardians(
        Wallet    storage  wallet,
        address[] calldata newGuardians
        )
        external
    {
        Guardian[] memory allGuardians = guardians(wallet, true);
        for (uint i = 0; i < allGuardians.length; i++) {
            _removeGuardian(wallet, allGuardians[i].addr, GUARDIAN_PENDING_PERIOD, false);
        }

        for (uint j = 0; j < newGuardians.length; j++) {
            _addGuardian(wallet, newGuardians[j], GUARDIAN_PENDING_PERIOD, false);
        }
    }

    function resetGuardiansWA(
        Wallet    storage  wallet,
        bytes32            domainSeparator,
        Approval  calldata approval,
        address[] calldata newGuardians
        )
        external
        returns (bytes32 approvedHash)
    {
        approvedHash = wallet.verifyApproval(
            domainSeparator,
            SigRequirement.MAJORITY_OWNER_REQUIRED,
            approval,
            abi.encode(
                RESET_GUARDIANS_TYPEHASH,
                approval.wallet,
                approval.validUntil,
                keccak256(abi.encodePacked(newGuardians))
            )
        );

        removeAllGuardians(wallet);
        for (uint i = 0; i < newGuardians.length; i++) {
            _addGuardian(wallet, newGuardians[i], 0, true);
        }
    }

    function requireMajority(
        Wallet         storage wallet,
        address[]      memory  signers,
        SigRequirement         requirement
        )
        internal
        view
        returns (bool)
    {
        // We always need at least one signer
        if (signers.length == 0) {
            return false;
        }

        // Calculate total group sizes
        Guardian[] memory allGuardians = guardians(wallet, false);
        require(allGuardians.length > 0, "NO_GUARDIANS");

        address lastSigner;
        bool walletOwnerSigned = false;
        address owner = wallet.owner;
        for (uint i = 0; i < signers.length; i++) {
            // Check for duplicates
            require(signers[i] > lastSigner, "INVALID_SIGNERS_ORDER");
            lastSigner = signers[i];

            if (signers[i] == owner) {
                walletOwnerSigned = true;
            } else {
                bool _isGuardian = false;
                for (uint j = 0; j < allGuardians.length; j++) {
                    if (allGuardians[j].addr == signers[i]) {
                        _isGuardian = true;
                        break;
                    }
                }
                require(_isGuardian, "SIGNER_NOT_GUARDIAN");
            }
        }

        if (requirement == SigRequirement.OWNER_OR_ANY_GUARDIAN) {
            return signers.length == 1;
        } else if (requirement == SigRequirement.ANY_GUARDIAN) {
            require(!walletOwnerSigned, "WALLET_OWNER_SIGNATURE_NOT_ALLOWED");
            return signers.length == 1;
        }

        // Check owner requirements
        if (requirement == SigRequirement.MAJORITY_OWNER_REQUIRED) {
            require(walletOwnerSigned, "WALLET_OWNER_SIGNATURE_REQUIRED");
        } else if (requirement == SigRequirement.MAJORITY_OWNER_NOT_ALLOWED) {
            require(!walletOwnerSigned, "WALLET_OWNER_SIGNATURE_NOT_ALLOWED");
        }

        uint numExtendedSigners = allGuardians.length;
        if (walletOwnerSigned) {
            numExtendedSigners += 1;
            require(signers.length > 1, "NO_GUARDIAN_SIGNED_BESIDES_OWNER");
        }

        return signers.length >= (numExtendedSigners >> 1) + 1;
    }

    function isGuardian(
        Wallet storage wallet,
        address addr,
        bool    includePendingAddition
        )
        public
        view
        returns (bool)
    {
        Guardian memory g = _getGuardian(wallet, addr);
        return _isActiveOrPendingAddition(g, includePendingAddition);
    }

    function guardians(
        Wallet storage wallet,
        bool    includePendingAddition
        )
        public
        view
        returns (Guardian[] memory _guardians)
    {
        _guardians = new Guardian[](wallet.guardians.length);
        uint index = 0;
        for (uint i = 0; i < wallet.guardians.length; i++) {
            Guardian memory g = wallet.guardians[i];
            if (_isActiveOrPendingAddition(g, includePendingAddition)) {
                _guardians[index] = g;
                index++;
            }
        }
        assembly { mstore(_guardians, index) }
    }

    function numGuardians(
        Wallet storage wallet,
        bool    includePendingAddition
        )
        public
        view
        returns (uint count)
    {
        for (uint i = 0; i < wallet.guardians.length; i++) {
            Guardian memory g = wallet.guardians[i];
            if (_isActiveOrPendingAddition(g, includePendingAddition)) {
                count++;
            }
        }
    }

     function removeAllGuardians(
        Wallet storage wallet
        )
        internal
    {
        uint size = wallet.guardians.length;
        if (size == 0) return;

        for (uint i = 0; i < wallet.guardians.length; i++) {
            delete wallet.guardianIdx[wallet.guardians[i].addr];
        }
        delete wallet.guardians;
    }

    function cancelPendingGuardians(Wallet storage wallet)
        internal
    {
        bool cancelled = false;
        for (uint i = 0; i < wallet.guardians.length; i++) {
            Guardian memory g = wallet.guardians[i];
            if (_isPendingAddition(g)) {
                wallet.guardians[i].status = uint8(GuardianStatus.REMOVE);
                wallet.guardians[i].timestamp = 0;
                cancelled = true;
            }
            if (_isPendingRemoval(g)) {
                wallet.guardians[i].status = uint8(GuardianStatus.ADD);
                wallet.guardians[i].timestamp = 0;
                cancelled = true;
            }
        }
        _cleanRemovedGuardians(wallet, true);
    }

    function storeGuardian(
        Wallet storage wallet,
        address addr,
        uint    validSince,
        bool    alwaysOverride
        )
        internal
        returns (uint)
    {
        require(validSince >= block.timestamp, "INVALID_VALID_SINCE");
        require(addr != address(0), "ZERO_ADDRESS");
        require(addr != address(this), "INVALID_ADDRESS");

        uint pos = wallet.guardianIdx[addr];

        if (pos == 0) {
            // Add the new guardian
            Guardian memory _g = Guardian(
                addr,
                uint8(GuardianStatus.ADD),
                validSince.toUint64()
            );
            wallet.guardians.push(_g);
            wallet.guardianIdx[addr] = wallet.guardians.length;

            _cleanRemovedGuardians(wallet, false);
            return validSince;
        }

        Guardian memory g = wallet.guardians[pos - 1];

        if (_isRemoved(g)) {
            wallet.guardians[pos - 1].status = uint8(GuardianStatus.ADD);
            wallet.guardians[pos - 1].timestamp = validSince.toUint64();
            return validSince;
        }

        if (_isPendingRemoval(g)) {
            wallet.guardians[pos - 1].status = uint8(GuardianStatus.ADD);
            wallet.guardians[pos - 1].timestamp = 0;
            return 0;
        }

        if (_isPendingAddition(g)) {
            if (!alwaysOverride) return g.timestamp;

            wallet.guardians[pos - 1].timestamp = validSince.toUint64();
            return validSince;
        }

        require(_isAdded(g), "UNEXPECTED_RESULT");
        return 0;
    }

    function deleteGuardian(
        Wallet storage wallet,
        address addr,
        uint    validUntil,
        bool    alwaysOverride
        )
        internal
        returns (uint)
    {
        require(validUntil >= block.timestamp, "INVALID_VALID_UNTIL");
        require(addr != address(0), "ZERO_ADDRESS");

        uint pos = wallet.guardianIdx[addr];
        require(pos > 0, "GUARDIAN_NOT_EXISTS");

        Guardian memory g = wallet.guardians[pos - 1];

        if (_isAdded(g)) {
            wallet.guardians[pos - 1].status = uint8(GuardianStatus.REMOVE);
            wallet.guardians[pos - 1].timestamp = validUntil.toUint64();
            return validUntil;
        }

        if (_isPendingAddition(g)) {
            wallet.guardians[pos - 1].status = uint8(GuardianStatus.REMOVE);
            wallet.guardians[pos - 1].timestamp = 0;
            return 0;
        }

        if (_isPendingRemoval(g)) {
            if (!alwaysOverride) return g.timestamp;

            wallet.guardians[pos - 1].timestamp = validUntil.toUint64();
            return validUntil;
        }

        require(_isRemoved(g), "UNEXPECTED_RESULT");
        return 0;
    }

    // --- Internal functions ---

    function _addGuardian(
        Wallet storage wallet,
        address guardian,
        uint    pendingPeriod,
        bool    alwaysOverride
        )
        internal
    {
        uint _numGuardians = numGuardians(wallet, true);
        require(_numGuardians < MAX_GUARDIANS, "TOO_MANY_GUARDIANS");
        require(guardian != wallet.owner, "GUARDIAN_CAN_NOT_BE_OWNER");

        uint validSince = block.timestamp;
        if (_numGuardians >= 2) {
            validSince = block.timestamp + pendingPeriod;
        }
        validSince = storeGuardian(wallet, guardian, validSince, alwaysOverride);
        emit GuardianAdded(guardian, validSince);
    }

    function _removeGuardian(
        Wallet storage wallet,
        address guardian,
        uint    pendingPeriod,
        bool    alwaysOverride
        )
        private
    {
        uint validUntil = block.timestamp + pendingPeriod;
        validUntil = deleteGuardian(wallet, guardian, validUntil, alwaysOverride);
        emit GuardianRemoved(guardian, validUntil);
    }

    function _getGuardian(
        Wallet storage wallet,
        address addr
        )
        private
        view
        returns (Guardian memory guardian)
    {
        uint pos = wallet.guardianIdx[addr];
        if (pos > 0) {
            guardian = wallet.guardians[pos - 1];
        }
    }

    function _isAdded(Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return guardian.status == uint8(GuardianStatus.ADD) &&
            guardian.timestamp <= block.timestamp;
    }

    function _isPendingAddition(Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return guardian.status == uint8(GuardianStatus.ADD) &&
            guardian.timestamp > block.timestamp;
    }

    function _isRemoved(Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return guardian.status == uint8(GuardianStatus.REMOVE) &&
            guardian.timestamp <= block.timestamp;
    }

    function _isPendingRemoval(Guardian memory guardian)
        private
        view
        returns (bool)
    {
         return guardian.status == uint8(GuardianStatus.REMOVE) &&
            guardian.timestamp > block.timestamp;
    }

    function _isActive(Guardian memory guardian)
        private
        view
        returns (bool)
    {
        return _isAdded(guardian) || _isPendingRemoval(guardian);
    }

    function _isActiveOrPendingAddition(
        Guardian memory guardian,
        bool includePendingAddition
        )
        private
        view
        returns (bool)
    {
        return _isActive(guardian) || includePendingAddition && _isPendingAddition(guardian);
    }

    function _cleanRemovedGuardians(
        Wallet storage wallet,
        bool    force
        )
        private
    {
        uint count = wallet.guardians.length;
        if (!force && count < 10) return;

        for (int i = int(count) - 1; i >= 0; i--) {
            Guardian memory g = wallet.guardians[uint(i)];
            if (_isRemoved(g)) {
                Guardian memory lastGuardian = wallet.guardians[wallet.guardians.length - 1];

                if (g.addr != lastGuardian.addr) {
                    wallet.guardians[uint(i)] = lastGuardian;
                    wallet.guardianIdx[lastGuardian.addr] = uint(i) + 1;
                }
                wallet.guardians.pop();
                delete wallet.guardianIdx[g.addr];
            }
        }
    }
}

File 2 of 10 : WalletData.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

enum SigRequirement
{
    MAJORITY_OWNER_NOT_ALLOWED,
    MAJORITY_OWNER_ALLOWED,
    MAJORITY_OWNER_REQUIRED,
    OWNER_OR_ANY_GUARDIAN,
    ANY_GUARDIAN
}

struct Approval
{
    address[] signers;
    bytes[]   signatures;
    uint      validUntil;
    address   wallet;
}

// Optimized to fit into 64 bytes (2 slots)
struct Quota
{
    uint128 currentQuota;
    uint128 pendingQuota;
    uint128 spentAmount;
    uint64  spentTimestamp;
    uint64  pendingUntil;
}

enum GuardianStatus
{
    REMOVE,    // Being removed or removed after validUntil timestamp
    ADD        // Being added or added after validSince timestamp.
}

// Optimized to fit into 32 bytes (1 slot)
struct Guardian
{
    address addr;
    uint8   status;
    uint64  timestamp; // validSince if status = ADD; validUntil if adding = REMOVE;
}

struct Wallet
{
    address owner;
    uint64  creationTimestamp;

    // relayer => nonce
    uint nonce;
    // hash => consumed
    mapping (bytes32 => bool) hashes;

    bool    locked;

    Guardian[] guardians;
    mapping (address => uint)  guardianIdx;

    address    inheritor;
    uint32     inheritWaitingPeriod;
    uint64     lastActive; // the latest timestamp the owner is considered to be active

    Quota quota;

    // whitelisted address => effective timestamp
    mapping (address => uint) whitelisted;
}

File 3 of 10 : ApprovalLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../../lib/EIP712.sol";
import "../../lib/SignatureUtil.sol";
import "./GuardianLib.sol";
import "./WalletData.sol";


/// @title ApprovalLib
/// @dev Utility library for better handling of signed wallet requests.
///      This library must be deployed and linked to other modules.
///
/// @author Daniel Wang - <[email protected]>
library ApprovalLib {
    using SignatureUtil for bytes32;

    function verifyApproval(
        Wallet  storage wallet,
        bytes32         domainSeparator,
        SigRequirement  sigRequirement,
        Approval memory approval,
        bytes    memory encodedRequest
        )
        internal
        returns (bytes32 approvedHash)
    {
        require(address(this) == approval.wallet, "INVALID_WALLET");
        require(block.timestamp <= approval.validUntil, "EXPIRED_SIGNED_REQUEST");

        approvedHash = EIP712.hashPacked(domainSeparator, keccak256(encodedRequest));

        // Save hash to prevent replay attacks
        require(!wallet.hashes[approvedHash], "HASH_EXIST");
        wallet.hashes[approvedHash] = true;

        require(
            approvedHash.verifySignatures(approval.signers, approval.signatures),
            "INVALID_SIGNATURES"
        );

        require(
            GuardianLib.requireMajority(
                wallet,
                approval.signers,
                sigRequirement
            ),
            "PERMISSION_DENIED"
        );
    }
}

File 4 of 10 : SignatureUtil.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;

import "../thirdparty/BytesUtil.sol";
import "./AddressUtil.sol";
import "./ERC1271.sol";
import "./MathUint.sol";


/// @title SignatureUtil
/// @author Daniel Wang - <[email protected]>
/// @dev This method supports multihash standard. Each signature's last byte indicates
///      the signature's type.
library SignatureUtil
{
    using BytesUtil     for bytes;
    using MathUint      for uint;
    using AddressUtil   for address;

    enum SignatureType {
        ILLEGAL,
        INVALID,
        EIP_712,
        ETH_SIGN,
        WALLET   // deprecated
    }

    bytes4 constant internal ERC1271_MAGICVALUE = 0x1626ba7e;

    function verifySignatures(
        bytes32          signHash,
        address[] memory signers,
        bytes[]   memory signatures
        )
        internal
        view
        returns (bool)
    {
        require(signers.length == signatures.length, "BAD_SIGNATURE_DATA");
        address lastSigner;
        for (uint i = 0; i < signers.length; i++) {
            require(signers[i] > lastSigner, "INVALID_SIGNERS_ORDER");
            lastSigner = signers[i];
            if (!verifySignature(signHash, signers[i], signatures[i])) {
                return false;
            }
        }
        return true;
    }

    function verifySignature(
        bytes32        signHash,
        address        signer,
        bytes   memory signature
        )
        internal
        view
        returns (bool)
    {
        if (signer == address(0)) {
            return false;
        }

        return signer.isContract()?
            verifyERC1271Signature(signHash, signer, signature):
            verifyEOASignature(signHash, signer, signature);
    }

    function recoverECDSASigner(
        bytes32      signHash,
        bytes memory signature
        )
        internal
        pure
        returns (address)
    {
        if (signature.length != 65) {
            return address(0);
        }

        bytes32 r;
        bytes32 s;
        uint8   v;
        // we jump 32 (0x20) as the first slot of bytes contains the length
        // we jump 65 (0x41) per signature
        // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := and(mload(add(signature, 0x41)), 0xff)
        }
        // See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return address(0);
        }
        if (v == 27 || v == 28) {
            return ecrecover(signHash, v, r, s);
        } else {
            return address(0);
        }
    }

    function verifyEOASignature(
        bytes32        signHash,
        address        signer,
        bytes   memory signature
        )
        private
        pure
        returns (bool success)
    {
        if (signer == address(0)) {
            return false;
        }

        uint signatureTypeOffset = signature.length.sub(1);
        SignatureType signatureType = SignatureType(signature.toUint8(signatureTypeOffset));

        // Strip off the last byte of the signature by updating the length
        assembly {
            mstore(signature, signatureTypeOffset)
        }

        if (signatureType == SignatureType.EIP_712) {
            success = (signer == recoverECDSASigner(signHash, signature));
        } else if (signatureType == SignatureType.ETH_SIGN) {
            bytes32 hash = keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", signHash)
            );
            success = (signer == recoverECDSASigner(hash, signature));
        } else {
            success = false;
        }

        // Restore the signature length
        assembly {
            mstore(signature, add(signatureTypeOffset, 1))
        }

        return success;
    }

    function verifyERC1271Signature(
        bytes32 signHash,
        address signer,
        bytes   memory signature
        )
        private
        view
        returns (bool)
    {
        bytes memory callData = abi.encodeWithSelector(
            ERC1271.isValidSignature.selector,
            signHash,
            signature
        );
        (bool success, bytes memory result) = signer.staticcall(callData);
        return (
            success &&
            result.length == 32 &&
            result.toBytes4(0) == ERC1271_MAGICVALUE
        );
    }
}

File 5 of 10 : SafeCast.sol
// SPDX-License-Identifier: MIT
// Taken from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/SafeCast.sol

pragma solidity ^0.7.0;


/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2**128, "SafeCast: value doesn\'t fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        require(value < 2**96, "SafeCast: value doesn\'t fit in 96 bits");
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2**64, "SafeCast: value doesn\'t fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2**32, "SafeCast: value doesn\'t fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value < 2**40, "SafeCast: value doesn\'t fit in 40 bits");
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2**16, "SafeCast: value doesn\'t fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2**8, "SafeCast: value doesn\'t fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\'t fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\'t fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\'t fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\'t fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\'t fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2**255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

File 6 of 10 : EIP712.sol
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;


library EIP712
{
    struct Domain {
        string  name;
        string  version;
        address verifyingContract;
    }

    bytes32 constant internal EIP712_DOMAIN_TYPEHASH = keccak256(
        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
    );

    string constant internal EIP191_HEADER = "\x19\x01";

    function hash(Domain memory domain)
        internal
        pure
        returns (bytes32)
    {
        uint _chainid;
        assembly { _chainid := chainid() }

        return keccak256(
            abi.encode(
                EIP712_DOMAIN_TYPEHASH,
                keccak256(bytes(domain.name)),
                keccak256(bytes(domain.version)),
                _chainid,
                domain.verifyingContract
            )
        );
    }

    function hashPacked(
        bytes32 domainSeparator,
        bytes32 dataHash
        )
        internal
        pure
        returns (bytes32)
    {
        return keccak256(
            abi.encodePacked(
                EIP191_HEADER,
                domainSeparator,
                dataHash
            )
        );
    }
}

File 7 of 10 : BytesUtil.sol
// SPDX-License-Identifier: UNLICENSED
// Taken from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol
pragma solidity ^0.7.0;

library BytesUtil {
    function slice(
        bytes memory _bytes,
        uint _start,
        uint _length
    )
        internal
        pure
        returns (bytes memory)
    {
        require(_bytes.length >= (_start + _length));

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    mstore(mc, mload(cc))
                }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint _start) internal  pure returns (address) {
        require(_bytes.length >= (_start + 20));
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint _start) internal  pure returns (uint8) {
        require(_bytes.length >= (_start + 1));
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint _start) internal  pure returns (uint16) {
        require(_bytes.length >= (_start + 2));
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint24(bytes memory _bytes, uint _start) internal  pure returns (uint24) {
        require(_bytes.length >= (_start + 3));
        uint24 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x3), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint _start) internal  pure returns (uint32) {
        require(_bytes.length >= (_start + 4));
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint _start) internal  pure returns (uint64) {
        require(_bytes.length >= (_start + 8));
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint _start) internal  pure returns (uint96) {
        require(_bytes.length >= (_start + 12));
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint _start) internal  pure returns (uint128) {
        require(_bytes.length >= (_start + 16));
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint(bytes memory _bytes, uint _start) internal  pure returns (uint256) {
        require(_bytes.length >= (_start + 32));
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes4(bytes memory _bytes, uint _start) internal  pure returns (bytes4) {
        require(_bytes.length >= (_start + 4));
        bytes4 tempBytes4;

        assembly {
            tempBytes4 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes4;
    }

    function toBytes32(bytes memory _bytes, uint _start) internal  pure returns (bytes32) {
        require(_bytes.length >= (_start + 32));
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function fastSHA256(
        bytes memory data
        )
        internal
        view
        returns (bytes32)
    {
        bytes32[] memory result = new bytes32[](1);
        bool success;
        assembly {
             let ptr := add(data, 32)
             success := staticcall(sub(gas(), 2000), 2, ptr, mload(data), add(result, 32), 32)
        }
        require(success, "SHA256_FAILED");
        return result[0];
    }
}

File 8 of 10 : AddressUtil.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @title Utility Functions for addresses
/// @author Daniel Wang - <[email protected]>
/// @author Brecht Devos - <[email protected]>
library AddressUtil
{
    using AddressUtil for *;

    function isContract(
        address addr
        )
        internal
        view
        returns (bool)
    {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(addr) }
        return (codehash != 0x0 &&
                codehash != 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470);
    }

    function toPayable(
        address addr
        )
        internal
        pure
        returns (address payable)
    {
        return payable(addr);
    }

    // Works like address.send but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETH(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        if (amount == 0) {
            return true;
        }
        address payable recipient = to.toPayable();
        /* solium-disable-next-line */
        (success,) = recipient.call{value: amount, gas: gasLimit}("");
    }

    // Works like address.transfer but with a customizable gas limit
    // Make sure your code is safe for reentrancy when using this function!
    function sendETHAndVerify(
        address to,
        uint    amount,
        uint    gasLimit
        )
        internal
        returns (bool success)
    {
        success = to.sendETH(amount, gasLimit);
        require(success, "TRANSFER_FAILURE");
    }

    // Works like call but is slightly more efficient when data
    // needs to be copied from memory to do the call.
    function fastCall(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bool success, bytes memory returnData)
    {
        if (to != address(0)) {
            assembly {
                // Do the call
                success := call(gasLimit, to, value, add(data, 32), mload(data), 0, 0)
                // Copy the return data
                let size := returndatasize()
                returnData := mload(0x40)
                mstore(returnData, size)
                returndatacopy(add(returnData, 32), 0, size)
                // Update free memory pointer
                mstore(0x40, add(returnData, add(32, size)))
            }
        }
    }

    // Like fastCall, but throws when the call is unsuccessful.
    function fastCallAndVerify(
        address to,
        uint    gasLimit,
        uint    value,
        bytes   memory data
        )
        internal
        returns (bytes memory returnData)
    {
        bool success;
        (success, returnData) = fastCall(to, gasLimit, value, data);
        if (!success) {
            assembly {
                revert(add(returnData, 32), mload(returnData))
            }
        }
    }
}

File 9 of 10 : ERC1271.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;

abstract contract ERC1271 {
    // bytes4(keccak256("isValidSignature(bytes32,bytes)")
    bytes4 constant internal ERC1271_MAGICVALUE = 0x1626ba7e;

    function isValidSignature(
        bytes32      _hash,
        bytes memory _signature)
        public
        view
        virtual
        returns (bytes4 magicValue);
}

File 10 of 10 : MathUint.sol
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright 2017 Loopring Technology Limited.
pragma solidity ^0.7.0;


/// @title Utility Functions for uint
/// @author Daniel Wang - <[email protected]>
library MathUint
{
    function mul(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a * b;
        require(a == 0 || c / a == b, "MUL_OVERFLOW");
    }

    function sub(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint)
    {
        require(b <= a, "SUB_UNDERFLOW");
        return a - b;
    }

    function add(
        uint a,
        uint b
        )
        internal
        pure
        returns (uint c)
    {
        c = a + b;
        require(c >= a, "ADD_OVERFLOW");
    }
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"effectiveTime","type":"uint256"}],"name":"GuardianAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"effectiveTime","type":"uint256"}],"name":"GuardianRemoved","type":"event"},{"inputs":[],"name":"ADD_GUARDIAN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_PENDING_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_GUARDIANS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REMOVE_GUARDIAN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RESET_GUARDIANS_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]

612ed2610026600b82828239805160001a60731461001957fe5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100ff5760003560e01c8063a643b107116100a1578063d132d1db11610070578063d132d1db14610234578063dd2225f81461023c578063ee3da3e31461024f578063f26cfb661461026f576100ff565b8063a643b107146101cc578063abe61cdd146101ec578063b4f212fa146101f4578063b9d8df1414610214576100ff565b8063422c1d37116100dd578063422c1d371461017c5780637abbb0d514610184578063912fce541461018c5780639668d94c146101ac576100ff565b806318d9ad711461010457806328c809351461012d5780633140f8cf1461014f575b600080fd5b61011761011236600461257b565b610277565b604051610124919061275e565b60405180910390f35b81801561013957600080fd5b5061014d6101483660046124ec565b6103b5565b005b81801561015b57600080fd5b5061016f61016a3660046125fc565b61044a565b60405161012491906127e5565b61016f61055b565b61016f610560565b81801561019857600080fd5b5061016f6101a736600461259d565b610584565b8180156101b857600080fd5b5061016f6101c736600461259d565b61062f565b6101df6101da3660046124b1565b610681565b60405161012491906127da565b61016f6106a5565b81801561020057600080fd5b5061014d61020f366004612536565b6106c9565b81801561022057600080fd5b5061014d61022f366004612486565b610789565b61016f61079d565b61016f61024a36600461257b565b6107c1565b81801561025b57600080fd5b5061014d61026a366004612486565b61088a565b61016f61089a565b600482015460609067ffffffffffffffff8111801561029557600080fd5b506040519080825280602002602001820160405280156102cf57816020015b6102bc612222565b8152602001906001900390816102b45790505b5090506000805b60048501548110156103ac5760008560040182815481106102f357fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff75010000000000000000000000000000000000000000009093049290921690820152905061037f81866108a1565b156103a3578084848151811061039157fe5b60209081029190910101526001909201915b506001016102d6565b50815292915050565b60006103c2846001610277565b905060005b81518110156103ff576103f7858383815181106103e057fe5b6020026020010151600001516203f48060006108cc565b6001016103c7565b5060005b828110156104435761043b8585858481811061041b57fe5b9050602002016020810190610430919061246c565b6203f480600061091d565b600101610403565b5050505050565b600061050585600261045b87612db2565b7f102814d4a80680694a960b0e7e29965fdc37164004692cb5868555ae49f38d4561048c60808a0160608b0161246c565b896040013589896040516020016104a4929190612677565b604051602081830303815290604052805190602001206040516020016104cd9493929190612822565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528a93929190610a17565b905061051086610bf0565b60005b82811015610551576105498785858481811061052b57fe5b9050602002016020810190610540919061246c565b6000600161091d565b600101610513565b5095945050505050565b600a81565b7fc2d601f9b2c71cd1f247d67d83d55307ed88800236d40a2069c0a6d2b207ef8481565b600061061784600261059586612db2565b7fc2d601f9b2c71cd1f247d67d83d55307ed88800236d40a2069c0a6d2b207ef846105c66080890160608a0161246c565b8860400135886040516020016105df94939291906127ee565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528993929190610a17565b90506106278583600060016108cc565b949350505050565b600061067184600261064086612db2565b7f3aea25321405f61fb6d5dfb4b53be5d64671d80dc2149264e167060f5996b67a6105c66080890160608a0161246c565b905061062785836000600161091d565b60008061068e8585610c70565b905061069a81846108a1565b9150505b9392505050565b7f102814d4a80680694a960b0e7e29965fdc37164004692cb5868555ae49f38d4581565b6000805b8251811015610783578173ffffffffffffffffffffffffffffffffffffffff168382815181106106f957fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1611610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c94565b60405180910390fd5b82818151811061076357fe5b6020026020010151915061077b84836000600161091d565b6001016106cd565b50505050565b61079982826203f480600061091d565b5050565b7f3aea25321405f61fb6d5dfb4b53be5d64671d80dc2149264e167060f5996b67a81565b6000805b60048401548110156108835760008460040182815481106107e257fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff75010000000000000000000000000000000000000000009093049290921690820152905061086e81856108a1565b1561087a576001909201915b506001016107c5565b5092915050565b61079982826203f48060006108cc565b6203f48081565b60006108ac83610d40565b806108c357508180156108c357506108c383610d62565b90505b92915050565b4282016108db85858385610d90565b90507fbc92161fee7c8f66fcc67cb974d0c9b1439030462bd0d5201c21b01f89355b23848260405161090e929190612738565b60405180910390a15050505050565b600061092a8560016107c1565b9050600a8110610966576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c00565b845473ffffffffffffffffffffffffffffffffffffffff858116911614156109ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612d39565b42600282106109c857504283015b6109d4868683866110c7565b90507f6276832b43b1ca1eab9c38b577dc5ba939a807f5ca7b7e5b6f1f09e80e487fad8582604051610a07929190612738565b60405180910390a1505050505050565b6000826060015173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614610a82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612b5b565b8260400151421115610ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e9061296e565b610ad185838051906020012061141f565b600081815260028801602052604090205490915060ff1615610b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612d02565b6000818152600287016020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055835190840151610b6c918391611489565b610ba2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612ccb565b610bb1868460000151866115b5565b610be7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612a4a565b95945050505050565b600481015480610c005750610c6d565b60005b6004830154811015610c5e57826005016000846004018381548110610c2457fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812055600101610c03565b50610799600483016000612242565b50565b610c78612222565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600584016020526040902054801561088357836004016001820381548110610cb857fe5b600091825260209182902060408051606081018252929091015473ffffffffffffffffffffffffffffffffffffffff8116835274010000000000000000000000000000000000000000810460ff1693830193909352750100000000000000000000000000000000000000000090920467ffffffffffffffff1691810191909152949350505050565b6000610d4b82611957565b80610d5a5750610d5a82611986565b90505b919050565b600060015b60ff16826020015160ff16148015610d5a575050604001514267ffffffffffffffff9091161190565b600042831015610dcc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906128c9565b73ffffffffffffffffffffffffffffffffffffffff8416610e19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612ab8565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260058601602052604090205480610e78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612bc9565b6000866004016001830381548110610e8c57fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff750100000000000000000000000000000000000000000090930492909216908201529050610f1781611957565b15610fae5760005b876004016001840381548110610f3157fe5b9060005260206000200160000160146101000a81548160ff021916908360ff160217905550610f5f8561198e565b876004016001840381548110610f7157fe5b9060005260206000200160000160156101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508492505050610627565b610fb781610d62565b156110485760005b876004016001840381548110610fd157fe5b9060005260206000200160000160146101000a81548160ff021916908360ff160217905550600087600401600184038154811061100a57fe5b9060005260206000200160000160156101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600092505050610627565b61105181611986565b1561107b5783611072576040015167ffffffffffffffff1691506106279050565b610f5f8561198e565b611084816119f5565b6110ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612937565b5060009695505050505050565b600042831015611103576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612b92565b73ffffffffffffffffffffffffffffffffffffffff8416611150576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612ab8565b73ffffffffffffffffffffffffffffffffffffffff84163014156111a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612900565b73ffffffffffffffffffffffffffffffffffffffff841660009081526005860160205260409020548061132c576040805160608101825273ffffffffffffffffffffffffffffffffffffffff871681526001602082015260009181016112058761198e565b67ffffffffffffffff90811690915260048901805460018101825560008281526020808220865193018054828801516040808a01519098167501000000000000000000000000000000000000000000027fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff60ff90921674010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff9889167fffffffffffffffffffffffff0000000000000000000000000000000000000000909516949094179390931692909217161790559254918b16815260058c01909252918120919091559091506113229088906119fd565b8492505050610627565b600086600401600183038154811061134057fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff7501000000000000000000000000000000000000000000909304929092169082015290506113cb816119f5565b156113d7576001610f1f565b6113e081611986565b156113ec576001610fbf565b6113f581610d62565b156114165783611072576040015167ffffffffffffffff1691506106279050565b61108481611957565b60006040518060400160405280600281526020017f1901000000000000000000000000000000000000000000000000000000000000815250838360405160200161146b939291906126e0565b60405160208183030381529060405280519060200120905092915050565b600081518351146114c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906129dc565b6000805b84518110156115a9578173ffffffffffffffffffffffffffffffffffffffff168582815181106114f657fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161161154b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612aef565b84818151811061155757fe5b602002602001015191506115928686838151811061157157fe5b602002602001015186848151811061158557fe5b6020026020010151611d6d565b6115a15760009250505061069e565b6001016114ca565b50600195945050505050565b60008251600014156115c95750600061069e565b60006115d6856000610277565b90506000815111611613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612a81565b8454600090819073ffffffffffffffffffffffffffffffffffffffff16815b87518110156117d7578373ffffffffffffffffffffffffffffffffffffffff1688828151811061165e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16116116b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612aef565b8781815181106116bf57fe5b602002602001015193508173ffffffffffffffffffffffffffffffffffffffff168882815181106116ec57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16141561171957600192506117cf565b6000805b86518110156117955789838151811061173257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1687828151811061175c57fe5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16141561178d5760019150611795565b60010161171d565b50806117cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906129a5565b505b600101611632565b5060038660048111156117e657fe5b14156117fc57865160011494505050505061069e565b600486600481111561180a57fe5b1415611858578115611848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c37565b865160011494505050505061069e565b600286600481111561186657fe5b14156118a857816118a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612a13565b6118f4565b60008660048111156118b657fe5b14156118f45781156118f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c37565b8351821561193d57600181019050600188511161193d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612b26565b600181901c60010188511015955050505050509392505050565b600060015b60ff16826020015160ff16148015610d5a575050604001514267ffffffffffffffff909116111590565b600080610d67565b60006801000000000000000082106119f1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180612e776026913960400191505060405180910390fd5b5090565b60008061195c565b600482015481158015611a105750600a81105b15611a1b5750610799565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81015b60008112610783576000846004018281548110611a5857fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff750100000000000000000000000000000000000000000090930492909216908201529050611ae3816119f5565b15611d4557600485018054600091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908110611b1e57fe5b600091825260209182902060408051606081018252929091015473ffffffffffffffffffffffffffffffffffffffff80821680855274010000000000000000000000000000000000000000830460ff1695850195909552750100000000000000000000000000000000000000000090910467ffffffffffffffff169183019190915284519193501614611cb55780866004018481548110611bbb57fe5b60009182526020808320845192018054858301516040968701517fffffffffffffffffffffffff000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff958616177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff90921691909102177fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000067ffffffffffffffff9092169190910217905584519091168252600589019052206001840190555b85600401805480611cc257fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffff0000000000000000000000000000000000000000000000000000000000169055909201909255835173ffffffffffffffffffffffffffffffffffffffff1682526005880190526040812055505b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01611a3f565b600073ffffffffffffffffffffffffffffffffffffffff8316611d925750600061069e565b611db18373ffffffffffffffffffffffffffffffffffffffff16611dd0565b611dc557611dc0848484611e07565b610627565b610627848484611f41565b6000813f801580159061069e57507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470141592915050565b600073ffffffffffffffffffffffffffffffffffffffff8316611e2c5750600061069e565b8151600090611e3c90600161209b565b90506000611e4a8483612112565b60ff166004811115611e5857fe5b82855290506002816004811115611e6b57fe5b1415611eb057611e7b868561212e565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149250611f34565b6003816004811115611ebe57fe5b1415611f2f57600086604051602001611ed79190612707565b604051602081830303815290604052805190602001209050611ef9818661212e565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614935050611f34565b600092505b5060010182529392505050565b600080631626ba7e60e01b8584604051602401611f5f929190612853565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808573ffffffffffffffffffffffffffffffffffffffff1683604051611fe691906126c4565b600060405180830381855afa9150503d8060008114612021576040519150601f19603f3d011682016040523d82523d6000602084013e612026565b606091505b5091509150818015612039575080516020145b801561209057507f1626ba7e0000000000000000000000000000000000000000000000000000000061206c826000612206565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b979650505050505050565b60008282111561210c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b50900390565b6000816001018351101561212557600080fd5b50016001015190565b60008151604114612141575060006108c6565b60208201516040830151604184015160ff167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561218757600093505050506108c6565b8060ff16601b148061219c57508060ff16601c145b156121fa57600186828585604051600081526020016040526040516121c494939291906128ab565b6020604051602081039080840390855afa1580156121e6573d6000803e3d6000fd5b5050506020604051035193505050506108c6565b600093505050506108c6565b6000816004018351101561221957600080fd5b50016020015190565b604080516060810182526000808252602082018190529181019190915290565b5080546000825590600052602060002090810190610c6d91905b808211156119f15780547fffffff000000000000000000000000000000000000000000000000000000000016815560010161225c565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d5d57600080fd5b60008083601f8401126122c7578182fd5b50813567ffffffffffffffff8111156122de578182fd5b60208301915083602080830285010111156122f857600080fd5b9250929050565b600082601f83011261230f578081fd5b8135602061232461231f83612d94565b612d70565b8281528181019085830183850287018401881015612340578586fd5b855b858110156123655761235382612292565b84529284019290840190600101612342565b5090979650505050505050565b6000601f8381840112612383578182fd5b8235602061239361231f83612d94565b82815281810190868301865b8581101561243757813589018a603f8201126123b9578889fd5b85810135604067ffffffffffffffff8211156123d157fe5b612400887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c85011601612d70565b8281528d82848601011115612413578b8cfd5b828285018a83013791820188018b905250855250928401929084019060010161239f565b509098975050505050505050565b80358015158114610d5d57600080fd5b600060808284031215612466578081fd5b50919050565b60006020828403121561247d578081fd5b6108c382612292565b60008060408385031215612498578081fd5b823591506124a860208401612292565b90509250929050565b6000806000606084860312156124c5578081fd5b833592506124d560208501612292565b91506124e360408501612445565b90509250925092565b600080600060408486031215612500578283fd5b83359250602084013567ffffffffffffffff81111561251d578283fd5b612529868287016122b6565b9497909650939450505050565b60008060408385031215612548578182fd5b82359150602083013567ffffffffffffffff811115612565578182fd5b612571858286016122ff565b9150509250929050565b6000806040838503121561258d578182fd5b823591506124a860208401612445565b600080600080608085870312156125b2578081fd5b8435935060208501359250604085013567ffffffffffffffff8111156125d6578182fd5b6125e287828801612455565b9250506125f160608601612292565b905092959194509250565b600080600080600060808688031215612613578081fd5b8535945060208601359350604086013567ffffffffffffffff80821115612638578283fd5b61264489838a01612455565b94506060880135915080821115612659578283fd5b50612666888289016122b6565b969995985093965092949392505050565b60008184825b858110156126b95773ffffffffffffffffffffffffffffffffffffffff6126a383612292565b168352602092830192919091019060010161267d565b509095945050505050565b600082516126d6818460208701612e4a565b9190910192915050565b600084516126f2818460208901612e4a565b91909101928352506020820152604001919050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b602080825282518282018190526000919060409081850190868401855b828110156127cd578151805173ffffffffffffffffffffffffffffffffffffffff1685528681015160ff168786015285015167ffffffffffffffff16858501526060909301929085019060010161277b565b5091979650505050505050565b901515815260200190565b90815260200190565b93845273ffffffffffffffffffffffffffffffffffffffff9283166020850152604084019190915216606082015260800190565b93845273ffffffffffffffffffffffffffffffffffffffff9290921660208401526040830152606082015260800190565b6000838252604060208301528251806040840152612878816060850160208701612e4a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b93845260ff9290921660208401526040830152606082015260800190565b60208082526013908201527f494e56414c49445f56414c49445f554e54494c00000000000000000000000000604082015260600190565b6020808252600f908201527f494e56414c49445f414444524553530000000000000000000000000000000000604082015260600190565b60208082526011908201527f554e45585045435445445f524553554c54000000000000000000000000000000604082015260600190565b60208082526016908201527f455850495245445f5349474e45445f5245515545535400000000000000000000604082015260600190565b60208082526013908201527f5349474e45525f4e4f545f475541524449414e00000000000000000000000000604082015260600190565b60208082526012908201527f4241445f5349474e41545552455f444154410000000000000000000000000000604082015260600190565b6020808252601f908201527f57414c4c45545f4f574e45525f5349474e41545552455f524551554952454400604082015260600190565b60208082526011908201527f5045524d495353494f4e5f44454e494544000000000000000000000000000000604082015260600190565b6020808252600c908201527f4e4f5f475541524449414e530000000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f5a45524f5f414444524553530000000000000000000000000000000000000000604082015260600190565b60208082526015908201527f494e56414c49445f5349474e4552535f4f524445520000000000000000000000604082015260600190565b6020808252818101527f4e4f5f475541524449414e5f5349474e45445f424553494445535f4f574e4552604082015260600190565b6020808252600e908201527f494e56414c49445f57414c4c4554000000000000000000000000000000000000604082015260600190565b60208082526013908201527f494e56414c49445f56414c49445f53494e434500000000000000000000000000604082015260600190565b60208082526013908201527f475541524449414e5f4e4f545f45584953545300000000000000000000000000604082015260600190565b60208082526012908201527f544f4f5f4d414e595f475541524449414e530000000000000000000000000000604082015260600190565b60208082526022908201527f57414c4c45545f4f574e45525f5349474e41545552455f4e4f545f414c4c4f5760408201527f4544000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526010908201527f494e56414c49445f4f52444552494e4700000000000000000000000000000000604082015260600190565b60208082526012908201527f494e56414c49445f5349474e4154555245530000000000000000000000000000604082015260600190565b6020808252600a908201527f484153485f455849535400000000000000000000000000000000000000000000604082015260600190565b60208082526019908201527f475541524449414e5f43414e5f4e4f545f42455f4f574e455200000000000000604082015260600190565b60405181810167ffffffffffffffff81118282101715612d8c57fe5b604052919050565b600067ffffffffffffffff821115612da857fe5b5060209081020190565b600060808236031215612dc3578081fd5b6040516080810167ffffffffffffffff8282108183111715612de157fe5b816040528435915080821115612df5578384fd5b612e01368387016122ff565b83526020850135915080821115612e16578384fd5b50612e2336828601612372565b60208301525060408301356040820152612e3f60608401612292565b606082015292915050565b60005b83811015612e65578181015183820152602001612e4d565b83811115610783575050600091015256fe53616665436173743a2076616c756520646f65736e27742066697420696e2036342062697473a264697066735822122032de4f17b1ee9c352873347acdc3586968a6c4debfdd725595ed5b41a4bf9a1d64736f6c63430007060033

Deployed Bytecode

0x7368d9686e4b4706c425e91e4cf762c09d7686cde730146080604052600436106100ff5760003560e01c8063a643b107116100a1578063d132d1db11610070578063d132d1db14610234578063dd2225f81461023c578063ee3da3e31461024f578063f26cfb661461026f576100ff565b8063a643b107146101cc578063abe61cdd146101ec578063b4f212fa146101f4578063b9d8df1414610214576100ff565b8063422c1d37116100dd578063422c1d371461017c5780637abbb0d514610184578063912fce541461018c5780639668d94c146101ac576100ff565b806318d9ad711461010457806328c809351461012d5780633140f8cf1461014f575b600080fd5b61011761011236600461257b565b610277565b604051610124919061275e565b60405180910390f35b81801561013957600080fd5b5061014d6101483660046124ec565b6103b5565b005b81801561015b57600080fd5b5061016f61016a3660046125fc565b61044a565b60405161012491906127e5565b61016f61055b565b61016f610560565b81801561019857600080fd5b5061016f6101a736600461259d565b610584565b8180156101b857600080fd5b5061016f6101c736600461259d565b61062f565b6101df6101da3660046124b1565b610681565b60405161012491906127da565b61016f6106a5565b81801561020057600080fd5b5061014d61020f366004612536565b6106c9565b81801561022057600080fd5b5061014d61022f366004612486565b610789565b61016f61079d565b61016f61024a36600461257b565b6107c1565b81801561025b57600080fd5b5061014d61026a366004612486565b61088a565b61016f61089a565b600482015460609067ffffffffffffffff8111801561029557600080fd5b506040519080825280602002602001820160405280156102cf57816020015b6102bc612222565b8152602001906001900390816102b45790505b5090506000805b60048501548110156103ac5760008560040182815481106102f357fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff75010000000000000000000000000000000000000000009093049290921690820152905061037f81866108a1565b156103a3578084848151811061039157fe5b60209081029190910101526001909201915b506001016102d6565b50815292915050565b60006103c2846001610277565b905060005b81518110156103ff576103f7858383815181106103e057fe5b6020026020010151600001516203f48060006108cc565b6001016103c7565b5060005b828110156104435761043b8585858481811061041b57fe5b9050602002016020810190610430919061246c565b6203f480600061091d565b600101610403565b5050505050565b600061050585600261045b87612db2565b7f102814d4a80680694a960b0e7e29965fdc37164004692cb5868555ae49f38d4561048c60808a0160608b0161246c565b896040013589896040516020016104a4929190612677565b604051602081830303815290604052805190602001206040516020016104cd9493929190612822565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528a93929190610a17565b905061051086610bf0565b60005b82811015610551576105498785858481811061052b57fe5b9050602002016020810190610540919061246c565b6000600161091d565b600101610513565b5095945050505050565b600a81565b7fc2d601f9b2c71cd1f247d67d83d55307ed88800236d40a2069c0a6d2b207ef8481565b600061061784600261059586612db2565b7fc2d601f9b2c71cd1f247d67d83d55307ed88800236d40a2069c0a6d2b207ef846105c66080890160608a0161246c565b8860400135886040516020016105df94939291906127ee565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528993929190610a17565b90506106278583600060016108cc565b949350505050565b600061067184600261064086612db2565b7f3aea25321405f61fb6d5dfb4b53be5d64671d80dc2149264e167060f5996b67a6105c66080890160608a0161246c565b905061062785836000600161091d565b60008061068e8585610c70565b905061069a81846108a1565b9150505b9392505050565b7f102814d4a80680694a960b0e7e29965fdc37164004692cb5868555ae49f38d4581565b6000805b8251811015610783578173ffffffffffffffffffffffffffffffffffffffff168382815181106106f957fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1611610757576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c94565b60405180910390fd5b82818151811061076357fe5b6020026020010151915061077b84836000600161091d565b6001016106cd565b50505050565b61079982826203f480600061091d565b5050565b7f3aea25321405f61fb6d5dfb4b53be5d64671d80dc2149264e167060f5996b67a81565b6000805b60048401548110156108835760008460040182815481106107e257fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff75010000000000000000000000000000000000000000009093049290921690820152905061086e81856108a1565b1561087a576001909201915b506001016107c5565b5092915050565b61079982826203f48060006108cc565b6203f48081565b60006108ac83610d40565b806108c357508180156108c357506108c383610d62565b90505b92915050565b4282016108db85858385610d90565b90507fbc92161fee7c8f66fcc67cb974d0c9b1439030462bd0d5201c21b01f89355b23848260405161090e929190612738565b60405180910390a15050505050565b600061092a8560016107c1565b9050600a8110610966576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c00565b845473ffffffffffffffffffffffffffffffffffffffff858116911614156109ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612d39565b42600282106109c857504283015b6109d4868683866110c7565b90507f6276832b43b1ca1eab9c38b577dc5ba939a807f5ca7b7e5b6f1f09e80e487fad8582604051610a07929190612738565b60405180910390a1505050505050565b6000826060015173ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614610a82576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612b5b565b8260400151421115610ac0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e9061296e565b610ad185838051906020012061141f565b600081815260028801602052604090205490915060ff1615610b1f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612d02565b6000818152600287016020908152604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055835190840151610b6c918391611489565b610ba2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612ccb565b610bb1868460000151866115b5565b610be7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612a4a565b95945050505050565b600481015480610c005750610c6d565b60005b6004830154811015610c5e57826005016000846004018381548110610c2457fe5b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001812055600101610c03565b50610799600483016000612242565b50565b610c78612222565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600584016020526040902054801561088357836004016001820381548110610cb857fe5b600091825260209182902060408051606081018252929091015473ffffffffffffffffffffffffffffffffffffffff8116835274010000000000000000000000000000000000000000810460ff1693830193909352750100000000000000000000000000000000000000000090920467ffffffffffffffff1691810191909152949350505050565b6000610d4b82611957565b80610d5a5750610d5a82611986565b90505b919050565b600060015b60ff16826020015160ff16148015610d5a575050604001514267ffffffffffffffff9091161190565b600042831015610dcc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906128c9565b73ffffffffffffffffffffffffffffffffffffffff8416610e19576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612ab8565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260058601602052604090205480610e78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612bc9565b6000866004016001830381548110610e8c57fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff750100000000000000000000000000000000000000000090930492909216908201529050610f1781611957565b15610fae5760005b876004016001840381548110610f3157fe5b9060005260206000200160000160146101000a81548160ff021916908360ff160217905550610f5f8561198e565b876004016001840381548110610f7157fe5b9060005260206000200160000160156101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508492505050610627565b610fb781610d62565b156110485760005b876004016001840381548110610fd157fe5b9060005260206000200160000160146101000a81548160ff021916908360ff160217905550600087600401600184038154811061100a57fe5b9060005260206000200160000160156101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550600092505050610627565b61105181611986565b1561107b5783611072576040015167ffffffffffffffff1691506106279050565b610f5f8561198e565b611084816119f5565b6110ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612937565b5060009695505050505050565b600042831015611103576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612b92565b73ffffffffffffffffffffffffffffffffffffffff8416611150576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612ab8565b73ffffffffffffffffffffffffffffffffffffffff84163014156111a0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612900565b73ffffffffffffffffffffffffffffffffffffffff841660009081526005860160205260409020548061132c576040805160608101825273ffffffffffffffffffffffffffffffffffffffff871681526001602082015260009181016112058761198e565b67ffffffffffffffff90811690915260048901805460018101825560008281526020808220865193018054828801516040808a01519098167501000000000000000000000000000000000000000000027fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff60ff90921674010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff73ffffffffffffffffffffffffffffffffffffffff9889167fffffffffffffffffffffffff0000000000000000000000000000000000000000909516949094179390931692909217161790559254918b16815260058c01909252918120919091559091506113229088906119fd565b8492505050610627565b600086600401600183038154811061134057fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff7501000000000000000000000000000000000000000000909304929092169082015290506113cb816119f5565b156113d7576001610f1f565b6113e081611986565b156113ec576001610fbf565b6113f581610d62565b156114165783611072576040015167ffffffffffffffff1691506106279050565b61108481611957565b60006040518060400160405280600281526020017f1901000000000000000000000000000000000000000000000000000000000000815250838360405160200161146b939291906126e0565b60405160208183030381529060405280519060200120905092915050565b600081518351146114c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906129dc565b6000805b84518110156115a9578173ffffffffffffffffffffffffffffffffffffffff168582815181106114f657fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff161161154b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612aef565b84818151811061155757fe5b602002602001015191506115928686838151811061157157fe5b602002602001015186848151811061158557fe5b6020026020010151611d6d565b6115a15760009250505061069e565b6001016114ca565b50600195945050505050565b60008251600014156115c95750600061069e565b60006115d6856000610277565b90506000815111611613576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612a81565b8454600090819073ffffffffffffffffffffffffffffffffffffffff16815b87518110156117d7578373ffffffffffffffffffffffffffffffffffffffff1688828151811061165e57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16116116b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612aef565b8781815181106116bf57fe5b602002602001015193508173ffffffffffffffffffffffffffffffffffffffff168882815181106116ec57fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16141561171957600192506117cf565b6000805b86518110156117955789838151811061173257fe5b602002602001015173ffffffffffffffffffffffffffffffffffffffff1687828151811061175c57fe5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16141561178d5760019150611795565b60010161171d565b50806117cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e906129a5565b505b600101611632565b5060038660048111156117e657fe5b14156117fc57865160011494505050505061069e565b600486600481111561180a57fe5b1415611858578115611848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c37565b865160011494505050505061069e565b600286600481111561186657fe5b14156118a857816118a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612a13565b6118f4565b60008660048111156118b657fe5b14156118f45781156118f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612c37565b8351821561193d57600181019050600188511161193d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161074e90612b26565b600181901c60010188511015955050505050509392505050565b600060015b60ff16826020015160ff16148015610d5a575050604001514267ffffffffffffffff909116111590565b600080610d67565b60006801000000000000000082106119f1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180612e776026913960400191505060405180910390fd5b5090565b60008061195c565b600482015481158015611a105750600a81105b15611a1b5750610799565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81015b60008112610783576000846004018281548110611a5857fe5b600091825260209182902060408051606081018252919092015473ffffffffffffffffffffffffffffffffffffffff8116825260ff740100000000000000000000000000000000000000008204169382019390935267ffffffffffffffff750100000000000000000000000000000000000000000090930492909216908201529050611ae3816119f5565b15611d4557600485018054600091907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908110611b1e57fe5b600091825260209182902060408051606081018252929091015473ffffffffffffffffffffffffffffffffffffffff80821680855274010000000000000000000000000000000000000000830460ff1695850195909552750100000000000000000000000000000000000000000090910467ffffffffffffffff169183019190915284519193501614611cb55780866004018481548110611bbb57fe5b60009182526020808320845192018054858301516040968701517fffffffffffffffffffffffff000000000000000000000000000000000000000090921673ffffffffffffffffffffffffffffffffffffffff958616177fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff167401000000000000000000000000000000000000000060ff90921691909102177fffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffff16750100000000000000000000000000000000000000000067ffffffffffffffff9092169190910217905584519091168252600589019052206001840190555b85600401805480611cc257fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffff0000000000000000000000000000000000000000000000000000000000169055909201909255835173ffffffffffffffffffffffffffffffffffffffff1682526005880190526040812055505b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01611a3f565b600073ffffffffffffffffffffffffffffffffffffffff8316611d925750600061069e565b611db18373ffffffffffffffffffffffffffffffffffffffff16611dd0565b611dc557611dc0848484611e07565b610627565b610627848484611f41565b6000813f801580159061069e57507fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470141592915050565b600073ffffffffffffffffffffffffffffffffffffffff8316611e2c5750600061069e565b8151600090611e3c90600161209b565b90506000611e4a8483612112565b60ff166004811115611e5857fe5b82855290506002816004811115611e6b57fe5b1415611eb057611e7b868561212e565b73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16149250611f34565b6003816004811115611ebe57fe5b1415611f2f57600086604051602001611ed79190612707565b604051602081830303815290604052805190602001209050611ef9818661212e565b73ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614935050611f34565b600092505b5060010182529392505050565b600080631626ba7e60e01b8584604051602401611f5f929190612853565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505090506000808573ffffffffffffffffffffffffffffffffffffffff1683604051611fe691906126c4565b600060405180830381855afa9150503d8060008114612021576040519150601f19603f3d011682016040523d82523d6000602084013e612026565b606091505b5091509150818015612039575080516020145b801561209057507f1626ba7e0000000000000000000000000000000000000000000000000000000061206c826000612206565b7fffffffff0000000000000000000000000000000000000000000000000000000016145b979650505050505050565b60008282111561210c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f5355425f554e444552464c4f5700000000000000000000000000000000000000604482015290519081900360640190fd5b50900390565b6000816001018351101561212557600080fd5b50016001015190565b60008151604114612141575060006108c6565b60208201516040830151604184015160ff167f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a082111561218757600093505050506108c6565b8060ff16601b148061219c57508060ff16601c145b156121fa57600186828585604051600081526020016040526040516121c494939291906128ab565b6020604051602081039080840390855afa1580156121e6573d6000803e3d6000fd5b5050506020604051035193505050506108c6565b600093505050506108c6565b6000816004018351101561221957600080fd5b50016020015190565b604080516060810182526000808252602082018190529181019190915290565b5080546000825590600052602060002090810190610c6d91905b808211156119f15780547fffffff000000000000000000000000000000000000000000000000000000000016815560010161225c565b803573ffffffffffffffffffffffffffffffffffffffff81168114610d5d57600080fd5b60008083601f8401126122c7578182fd5b50813567ffffffffffffffff8111156122de578182fd5b60208301915083602080830285010111156122f857600080fd5b9250929050565b600082601f83011261230f578081fd5b8135602061232461231f83612d94565b612d70565b8281528181019085830183850287018401881015612340578586fd5b855b858110156123655761235382612292565b84529284019290840190600101612342565b5090979650505050505050565b6000601f8381840112612383578182fd5b8235602061239361231f83612d94565b82815281810190868301865b8581101561243757813589018a603f8201126123b9578889fd5b85810135604067ffffffffffffffff8211156123d157fe5b612400887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c85011601612d70565b8281528d82848601011115612413578b8cfd5b828285018a83013791820188018b905250855250928401929084019060010161239f565b509098975050505050505050565b80358015158114610d5d57600080fd5b600060808284031215612466578081fd5b50919050565b60006020828403121561247d578081fd5b6108c382612292565b60008060408385031215612498578081fd5b823591506124a860208401612292565b90509250929050565b6000806000606084860312156124c5578081fd5b833592506124d560208501612292565b91506124e360408501612445565b90509250925092565b600080600060408486031215612500578283fd5b83359250602084013567ffffffffffffffff81111561251d578283fd5b612529868287016122b6565b9497909650939450505050565b60008060408385031215612548578182fd5b82359150602083013567ffffffffffffffff811115612565578182fd5b612571858286016122ff565b9150509250929050565b6000806040838503121561258d578182fd5b823591506124a860208401612445565b600080600080608085870312156125b2578081fd5b8435935060208501359250604085013567ffffffffffffffff8111156125d6578182fd5b6125e287828801612455565b9250506125f160608601612292565b905092959194509250565b600080600080600060808688031215612613578081fd5b8535945060208601359350604086013567ffffffffffffffff80821115612638578283fd5b61264489838a01612455565b94506060880135915080821115612659578283fd5b50612666888289016122b6565b969995985093965092949392505050565b60008184825b858110156126b95773ffffffffffffffffffffffffffffffffffffffff6126a383612292565b168352602092830192919091019060010161267d565b509095945050505050565b600082516126d6818460208701612e4a565b9190910192915050565b600084516126f2818460208901612e4a565b91909101928352506020820152604001919050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b602080825282518282018190526000919060409081850190868401855b828110156127cd578151805173ffffffffffffffffffffffffffffffffffffffff1685528681015160ff168786015285015167ffffffffffffffff16858501526060909301929085019060010161277b565b5091979650505050505050565b901515815260200190565b90815260200190565b93845273ffffffffffffffffffffffffffffffffffffffff9283166020850152604084019190915216606082015260800190565b93845273ffffffffffffffffffffffffffffffffffffffff9290921660208401526040830152606082015260800190565b6000838252604060208301528251806040840152612878816060850160208701612e4a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b93845260ff9290921660208401526040830152606082015260800190565b60208082526013908201527f494e56414c49445f56414c49445f554e54494c00000000000000000000000000604082015260600190565b6020808252600f908201527f494e56414c49445f414444524553530000000000000000000000000000000000604082015260600190565b60208082526011908201527f554e45585045435445445f524553554c54000000000000000000000000000000604082015260600190565b60208082526016908201527f455850495245445f5349474e45445f5245515545535400000000000000000000604082015260600190565b60208082526013908201527f5349474e45525f4e4f545f475541524449414e00000000000000000000000000604082015260600190565b60208082526012908201527f4241445f5349474e41545552455f444154410000000000000000000000000000604082015260600190565b6020808252601f908201527f57414c4c45545f4f574e45525f5349474e41545552455f524551554952454400604082015260600190565b60208082526011908201527f5045524d495353494f4e5f44454e494544000000000000000000000000000000604082015260600190565b6020808252600c908201527f4e4f5f475541524449414e530000000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f5a45524f5f414444524553530000000000000000000000000000000000000000604082015260600190565b60208082526015908201527f494e56414c49445f5349474e4552535f4f524445520000000000000000000000604082015260600190565b6020808252818101527f4e4f5f475541524449414e5f5349474e45445f424553494445535f4f574e4552604082015260600190565b6020808252600e908201527f494e56414c49445f57414c4c4554000000000000000000000000000000000000604082015260600190565b60208082526013908201527f494e56414c49445f56414c49445f53494e434500000000000000000000000000604082015260600190565b60208082526013908201527f475541524449414e5f4e4f545f45584953545300000000000000000000000000604082015260600190565b60208082526012908201527f544f4f5f4d414e595f475541524449414e530000000000000000000000000000604082015260600190565b60208082526022908201527f57414c4c45545f4f574e45525f5349474e41545552455f4e4f545f414c4c4f5760408201527f4544000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526010908201527f494e56414c49445f4f52444552494e4700000000000000000000000000000000604082015260600190565b60208082526012908201527f494e56414c49445f5349474e4154555245530000000000000000000000000000604082015260600190565b6020808252600a908201527f484153485f455849535400000000000000000000000000000000000000000000604082015260600190565b60208082526019908201527f475541524449414e5f43414e5f4e4f545f42455f4f574e455200000000000000604082015260600190565b60405181810167ffffffffffffffff81118282101715612d8c57fe5b604052919050565b600067ffffffffffffffff821115612da857fe5b5060209081020190565b600060808236031215612dc3578081fd5b6040516080810167ffffffffffffffff8282108183111715612de157fe5b816040528435915080821115612df5578384fd5b612e01368387016122ff565b83526020850135915080821115612e16578384fd5b50612e2336828601612372565b60208301525060408301356040820152612e3f60608401612292565b606082015292915050565b60005b83811015612e65578181015183820152602001612e4d565b83811115610783575050600091015256fe53616665436173743a2076616c756520646f65736e27742066697420696e2036342062697473a264697066735822122032de4f17b1ee9c352873347acdc3586968a6c4debfdd725595ed5b41a4bf9a1d64736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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.