ETH Price: $1,910.12 (-1.43%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

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:
ERC721Marketplace

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 15 : ERC721Marketplace.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import {ERC721MarketplaceInternal} from "./ERC721MarketplaceInternal.sol";
import {ScapesMarketplaceStorage} from "./ScapesMarketplaceStorage.sol";
import {ERC721BaseInternal} from "../solidstate/ERC721BaseInternal.sol";
import {ScapesERC721MetadataStorage} from "../ScapesERC721MetadataStorage.sol";
import {IChild} from "../IChild.sol";

/// @title ERC721Marketplace
/// @author akuti.eth, jalil.eth | scapes.eth
/// @notice Adds a marketplace to ERC721 tokens that only takes royalties when tokens are sold at a gain.
/// @dev A diamond facet that adds marketplace functionality to ERC721 tokens.
contract ERC721Marketplace is ERC721BaseInternal, ERC721MarketplaceInternal {
    uint256 internal constant INITIAL_LAST_PRICE = 0.1 ether;

    /// @notice Get an exisiting current offer.
    function getOffer(uint256 tokenId)
        external
        view
        returns (ScapesMarketplaceStorage.Offer memory offer)
    {
        ScapesMarketplaceStorage.Layout storage d = ScapesMarketplaceStorage
            .layout();
        offer = d.offers[tokenId];
        if (offer.price == 0) revert ERC721Marketplace__NonExistentOffer();
    }

    /// @notice List your token publicly.
    /// @dev Make an offer. Emits an {OfferCreated} event. An existing offer is replaced.
    function makeOffer(uint256 tokenId, uint80 price) external {
        // max price is 1_208_925 ETH
        _makeOffer(tokenId, price, address(0));
    }

    /// @notice List multiple tokens publicly.
    /// @dev Batch make offers. Emits an {OfferCreated} event for each offer. Existing offers are replaced.
    function batchMakeOffer(
        uint256[] calldata tokenIds,
        uint80[] calldata prices
    ) external {
        if (tokenIds.length != prices.length)
            revert ERC721Marketplace__InvalidArguments();
        uint256 length = tokenIds.length;
        for (uint256 i = 0; i < length; ) {
            _makeOffer(tokenIds[i], prices[i], address(0));
            unchecked {
                i++;
            }
        }
    }

    /// @notice List your token privately for one address.
    /// @dev Make a private offer. Emits an {OfferCreated} event. An existing offer is replaced.
    function makeOfferTo(
        uint256 tokenId,
        uint80 price,
        address to
    ) external {
        _makeOffer(tokenId, price, to);
    }

    /// @notice List multiple tokens privately for given addresses.
    /// @dev Batch make private offers. Emits an {OfferCreated} event for each offer. Existing offers are replaced.
    function batchMakeOfferTo(
        uint256[] calldata tokenIds,
        uint80[] calldata prices,
        address[] calldata tos
    ) external {
        if (tokenIds.length != prices.length || tokenIds.length != tos.length)
            revert ERC721Marketplace__InvalidArguments();
        uint256 length = tokenIds.length;
        for (uint256 i = 0; i < length; ) {
            _makeOffer(tokenIds[i], prices[i], tos[i]);
            unchecked {
                i++;
            }
        }
    }

    /// @notice Cancel an existing offer.
    /// @dev Allow approved operators to cancel an offer. Emits an {OfferWithdrawn} event.
    function cancelOffer(uint256 tokenId) public {
        if (!_isApprovedOrOwner(msg.sender, tokenId))
            revert ERC721Base__NotOwnerOrApproved();
        _cancelOffer(tokenId);
    }

    /// @notice Cancel multiple existing offers.
    /// @dev Allow approved operators to cancel existing offers. Emits an {OfferWithdrawn} event for each offer.
    function batchCancelOffer(uint256[] calldata tokenIds) external {
        uint256 length = tokenIds.length;
        for (uint256 i = 0; i < length; ) {
            cancelOffer(tokenIds[i]);
            unchecked {
                i++;
            }
        }
    }

    /// @notice Buy an offered item.
    /// @dev Buy an item that is offered publicly or to the sender. Emits a {Sale} event.
    function buy(uint256 tokenId) external payable {
        ScapesMarketplaceStorage.Offer memory offer = ScapesMarketplaceStorage
            .layout()
            .offers[tokenId];
        if (offer.price > 0 && msg.value != offer.price)
            revert ERC721Marketplace__InvalidValue();
        _buy(tokenId, offer);
    }

    /// @notice Buy multiple offered items.
    /// @dev Batch buy items that are offered publicly or to the sender. Emits a {Sale} event for each sale.
    function batchBuy(uint256[] calldata tokenIds) external payable {
        ScapesMarketplaceStorage.Layout storage d = ScapesMarketplaceStorage
            .layout();
        uint256 totalCost;
        uint256 length = tokenIds.length;
        for (uint256 i = 0; i < length; ) {
            ScapesMarketplaceStorage.Offer memory offer = d.offers[tokenIds[i]];
            totalCost += offer.price;
            if (msg.value < totalCost) revert ERC721Marketplace__InvalidValue();
            _buy(tokenIds[i], offer);
            unchecked {
                i++;
            }
        }
        if (msg.value > totalCost) revert ERC721Marketplace__InvalidValue();
    }

    /// @dev Logic of the buy function, check that item is offered, sent value
    ///      is correct and caluclate correct fee to apply
    function _buy(uint256 tokenId, ScapesMarketplaceStorage.Offer memory offer)
        internal
    {
        uint256 price = offer.price;
        uint256 lastPrice = (offer.lastPrice == 0)
            ? INITIAL_LAST_PRICE
            : offer.lastPrice;
        if (price == 0) revert ERC721Marketplace__NonExistentOffer();
        // If it is a private sale, make sure the buyer is the private sale recipient.
        if (
            offer.specificBuyer != address(0) &&
            offer.specificBuyer != msg.sender
        ) {
            revert ERC721Marketplace__NonExistentOffer();
        }
        if (msg.value < offer.price) revert ERC721Marketplace__InvalidValue();
        ScapesMarketplaceStorage.Layout storage d = ScapesMarketplaceStorage
            .layout();

        // Keep track of the last price of the token.
        d.offers[tokenId].lastPrice = offer.price;

        // Close Offer
        d.offers[tokenId].price = 0;
        if (offer.specificBuyer != address(0))
            d.offers[tokenId].specificBuyer = address(0);

        // Seller gets msg value - fees set as BPS.
        address seller = _ownerOf(tokenId);
        if (lastPrice < offer.price) {
            uint256 fullFeePrice = (10_000 * lastPrice) / (10_000 - d.bps);
            uint256 fee = price < fullFeePrice
                ? price - lastPrice
                : (price * d.bps) / 10_000;
            _transferEtherAndCheck(seller, price - fee);
            _transferEtherAndCheck(d.beneficiary, fee);
        } else {
            _transferEtherAndCheck(seller, msg.value);
        }

        _safeTransfer(seller, msg.sender, tokenId, "");
        emit Sale(tokenId, seller, msg.sender, price);
    }

    function _transferEtherAndCheck(address receiver, uint256 value) internal {
        (bool sent, ) = payable(receiver).call{gas: 3_000, value: value}("");
        if (!sent) revert ERC721Marketplace__PaymentFailed();
    }

    /**
     * @inheritdoc ERC721BaseInternal
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override(ERC721BaseInternal) {
        IChild(ScapesERC721MetadataStorage.layout().scapeBound).update(
            from,
            to,
            tokenId
        );
        super._afterTokenTransfer(from, to, tokenId);
    }
}

File 2 of 15 : EnumerableMap.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Map implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableMap {
    error EnumerableMap__IndexOutOfBounds();
    error EnumerableMap__NonExistentKey();

    struct MapEntry {
        bytes32 _key;
        bytes32 _value;
    }

    struct Map {
        MapEntry[] _entries;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct AddressToAddressMap {
        Map _inner;
    }

    struct UintToAddressMap {
        Map _inner;
    }

    function at(
        AddressToAddressMap storage map,
        uint256 index
    ) internal view returns (address, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);

        return (
            address(uint160(uint256(key))),
            address(uint160(uint256(value)))
        );
    }

    function at(
        UintToAddressMap storage map,
        uint256 index
    ) internal view returns (uint256, address) {
        (bytes32 key, bytes32 value) = _at(map._inner, index);
        return (uint256(key), address(uint160(uint256(value))));
    }

    function contains(
        AddressToAddressMap storage map,
        address key
    ) internal view returns (bool) {
        return _contains(map._inner, bytes32(uint256(uint160(key))));
    }

    function contains(
        UintToAddressMap storage map,
        uint256 key
    ) internal view returns (bool) {
        return _contains(map._inner, bytes32(key));
    }

    function length(
        AddressToAddressMap storage map
    ) internal view returns (uint256) {
        return _length(map._inner);
    }

    function length(
        UintToAddressMap storage map
    ) internal view returns (uint256) {
        return _length(map._inner);
    }

    function get(
        AddressToAddressMap storage map,
        address key
    ) internal view returns (address) {
        return
            address(
                uint160(
                    uint256(_get(map._inner, bytes32(uint256(uint160(key)))))
                )
            );
    }

    function get(
        UintToAddressMap storage map,
        uint256 key
    ) internal view returns (address) {
        return address(uint160(uint256(_get(map._inner, bytes32(key)))));
    }

    function set(
        AddressToAddressMap storage map,
        address key,
        address value
    ) internal returns (bool) {
        return
            _set(
                map._inner,
                bytes32(uint256(uint160(key))),
                bytes32(uint256(uint160(value)))
            );
    }

    function set(
        UintToAddressMap storage map,
        uint256 key,
        address value
    ) internal returns (bool) {
        return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
    }

    function remove(
        AddressToAddressMap storage map,
        address key
    ) internal returns (bool) {
        return _remove(map._inner, bytes32(uint256(uint160(key))));
    }

    function remove(
        UintToAddressMap storage map,
        uint256 key
    ) internal returns (bool) {
        return _remove(map._inner, bytes32(key));
    }

    function toArray(
        AddressToAddressMap storage map
    )
        internal
        view
        returns (address[] memory keysOut, address[] memory valuesOut)
    {
        uint256 len = map._inner._entries.length;

        keysOut = new address[](len);
        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._key))
                );
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function toArray(
        UintToAddressMap storage map
    )
        internal
        view
        returns (uint256[] memory keysOut, address[] memory valuesOut)
    {
        uint256 len = map._inner._entries.length;

        keysOut = new uint256[](len);
        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = uint256(map._inner._entries[i]._key);
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function keys(
        AddressToAddressMap storage map
    ) internal view returns (address[] memory keysOut) {
        uint256 len = map._inner._entries.length;

        keysOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._key))
                );
            }
        }
    }

    function keys(
        UintToAddressMap storage map
    ) internal view returns (uint256[] memory keysOut) {
        uint256 len = map._inner._entries.length;

        keysOut = new uint256[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                keysOut[i] = uint256(map._inner._entries[i]._key);
            }
        }
    }

    function values(
        AddressToAddressMap storage map
    ) internal view returns (address[] memory valuesOut) {
        uint256 len = map._inner._entries.length;

        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function values(
        UintToAddressMap storage map
    ) internal view returns (address[] memory valuesOut) {
        uint256 len = map._inner._entries.length;

        valuesOut = new address[](len);

        unchecked {
            for (uint256 i; i < len; ++i) {
                valuesOut[i] = address(
                    uint160(uint256(map._inner._entries[i]._value))
                );
            }
        }
    }

    function _at(
        Map storage map,
        uint256 index
    ) private view returns (bytes32, bytes32) {
        if (index >= map._entries.length)
            revert EnumerableMap__IndexOutOfBounds();

        MapEntry storage entry = map._entries[index];
        return (entry._key, entry._value);
    }

    function _contains(
        Map storage map,
        bytes32 key
    ) private view returns (bool) {
        return map._indexes[key] != 0;
    }

    function _length(Map storage map) private view returns (uint256) {
        return map._entries.length;
    }

    function _get(Map storage map, bytes32 key) private view returns (bytes32) {
        uint256 keyIndex = map._indexes[key];
        if (keyIndex == 0) revert EnumerableMap__NonExistentKey();
        unchecked {
            return map._entries[keyIndex - 1]._value;
        }
    }

    function _set(
        Map storage map,
        bytes32 key,
        bytes32 value
    ) private returns (bool) {
        uint256 keyIndex = map._indexes[key];

        if (keyIndex == 0) {
            map._entries.push(MapEntry({ _key: key, _value: value }));
            map._indexes[key] = map._entries.length;
            return true;
        } else {
            unchecked {
                map._entries[keyIndex - 1]._value = value;
            }
            return false;
        }
    }

    function _remove(Map storage map, bytes32 key) private returns (bool) {
        uint256 keyIndex = map._indexes[key];

        if (keyIndex != 0) {
            unchecked {
                MapEntry storage last = map._entries[map._entries.length - 1];

                // move last entry to now-vacant index
                map._entries[keyIndex - 1] = last;
                map._indexes[last._key] = keyIndex;
            }

            // clear last index
            map._entries.pop();
            delete map._indexes[key];

            return true;
        } else {
            return false;
        }
    }
}

File 3 of 15 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Set implementation with enumeration functions
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
 */
library EnumerableSet {
    error EnumerableSet__IndexOutOfBounds();

    struct Set {
        bytes32[] _values;
        // 1-indexed to allow 0 to signify nonexistence
        mapping(bytes32 => uint256) _indexes;
    }

    struct Bytes32Set {
        Set _inner;
    }

    struct AddressSet {
        Set _inner;
    }

    struct UintSet {
        Set _inner;
    }

    function at(
        Bytes32Set storage set,
        uint256 index
    ) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    function at(
        AddressSet storage set,
        uint256 index
    ) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    function at(
        UintSet storage set,
        uint256 index
    ) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    function contains(
        Bytes32Set storage set,
        bytes32 value
    ) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    function contains(
        AddressSet storage set,
        address value
    ) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    function contains(
        UintSet storage set,
        uint256 value
    ) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    function indexOf(
        Bytes32Set storage set,
        bytes32 value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, value);
    }

    function indexOf(
        AddressSet storage set,
        address value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, bytes32(uint256(uint160(value))));
    }

    function indexOf(
        UintSet storage set,
        uint256 value
    ) internal view returns (uint256) {
        return _indexOf(set._inner, bytes32(value));
    }

    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    function add(
        Bytes32Set storage set,
        bytes32 value
    ) internal returns (bool) {
        return _add(set._inner, value);
    }

    function add(
        AddressSet storage set,
        address value
    ) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    function remove(
        Bytes32Set storage set,
        bytes32 value
    ) internal returns (bool) {
        return _remove(set._inner, value);
    }

    function remove(
        AddressSet storage set,
        address value
    ) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    function remove(
        UintSet storage set,
        uint256 value
    ) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    function toArray(
        Bytes32Set storage set
    ) internal view returns (bytes32[] memory) {
        return set._inner._values;
    }

    function toArray(
        AddressSet storage set
    ) internal view returns (address[] memory) {
        bytes32[] storage values = set._inner._values;
        address[] storage array;

        assembly {
            array.slot := values.slot
        }

        return array;
    }

    function toArray(
        UintSet storage set
    ) internal view returns (uint256[] memory) {
        bytes32[] storage values = set._inner._values;
        uint256[] storage array;

        assembly {
            array.slot := values.slot
        }

        return array;
    }

    function _at(
        Set storage set,
        uint256 index
    ) private view returns (bytes32) {
        if (index >= set._values.length)
            revert EnumerableSet__IndexOutOfBounds();
        return set._values[index];
    }

    function _contains(
        Set storage set,
        bytes32 value
    ) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    function _indexOf(
        Set storage set,
        bytes32 value
    ) private view returns (uint256) {
        unchecked {
            return set._indexes[value] - 1;
        }
    }

    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    function _add(
        Set storage set,
        bytes32 value
    ) private returns (bool status) {
        if (!_contains(set, value)) {
            set._values.push(value);
            set._indexes[value] = set._values.length;
            status = true;
        }
    }

    function _remove(
        Set storage set,
        bytes32 value
    ) private returns (bool status) {
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            unchecked {
                bytes32 last = set._values[set._values.length - 1];

                // move last value to now-vacant index

                set._values[valueIndex - 1] = last;
                set._indexes[last] = valueIndex;
            }
            // clear last index

            set._values.pop();
            delete set._indexes[value];

            status = true;
        }
    }
}

File 4 of 15 : IERC721Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Partial ERC721 interface needed by internal functions
 */
interface IERC721Internal {
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 indexed tokenId
    );

    event Approval(
        address indexed owner,
        address indexed operator,
        uint256 indexed tokenId
    );

    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );
}

File 5 of 15 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

interface IERC721Receiver {
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 6 of 15 : IERC721BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC721Internal } from '../../../interfaces/IERC721Internal.sol';

/**
 * @title ERC721 base interface
 */
interface IERC721BaseInternal is IERC721Internal {
    error ERC721Base__NotOwnerOrApproved();
    error ERC721Base__SelfApproval();
    error ERC721Base__BalanceQueryZeroAddress();
    error ERC721Base__ERC721ReceiverNotImplemented();
    error ERC721Base__InvalidOwner();
    error ERC721Base__MintToZeroAddress();
    error ERC721Base__NonExistentToken();
    error ERC721Base__NotTokenOwner();
    error ERC721Base__TokenAlreadyMinted();
    error ERC721Base__TransferToZeroAddress();
}

File 7 of 15 : AddressUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { UintUtils } from './UintUtils.sol';

library AddressUtils {
    using UintUtils for uint256;

    error AddressUtils__InsufficientBalance();
    error AddressUtils__NotContract();
    error AddressUtils__SendValueFailed();

    function toString(address account) internal pure returns (string memory) {
        return uint256(uint160(account)).toHexString(20);
    }

    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    function sendValue(address payable account, uint256 amount) internal {
        (bool success, ) = account.call{ value: amount }('');
        if (!success) revert AddressUtils__SendValueFailed();
    }

    function functionCall(
        address target,
        bytes memory data
    ) internal returns (bytes memory) {
        return
            functionCall(target, data, 'AddressUtils: failed low-level call');
    }

    function functionCall(
        address target,
        bytes memory data,
        string memory error
    ) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, error);
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return
            functionCallWithValue(
                target,
                data,
                value,
                'AddressUtils: failed low-level call with value'
            );
    }

    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) internal returns (bytes memory) {
        if (value > address(this).balance)
            revert AddressUtils__InsufficientBalance();
        return _functionCallWithValue(target, data, value, error);
    }

    /**
     * @notice execute arbitrary external call with limited gas usage and amount of copied return data
     * @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License)
     * @param target recipient of call
     * @param gasAmount gas allowance for call
     * @param value native token value to include in call
     * @param maxCopy maximum number of bytes to copy from return data
     * @param data encoded call data
     * @return success whether call is successful
     * @return returnData copied return data
     */
    function excessivelySafeCall(
        address target,
        uint256 gasAmount,
        uint256 value,
        uint16 maxCopy,
        bytes memory data
    ) internal returns (bool success, bytes memory returnData) {
        returnData = new bytes(maxCopy);

        assembly {
            // execute external call via assembly to avoid automatic copying of return data
            success := call(
                gasAmount,
                target,
                value,
                add(data, 0x20),
                mload(data),
                0,
                0
            )

            // determine whether to limit amount of data to copy
            let toCopy := returndatasize()

            if gt(toCopy, maxCopy) {
                toCopy := maxCopy
            }

            // store the length of the copied bytes
            mstore(returnData, toCopy)

            // copy the bytes from returndata[0:toCopy]
            returndatacopy(add(returnData, 0x20), 0, toCopy)
        }
    }

    function _functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory error
    ) private returns (bytes memory) {
        if (!isContract(target)) revert AddressUtils__NotContract();

        (bool success, bytes memory returnData) = target.call{ value: value }(
            data
        );

        if (success) {
            return returnData;
        } else if (returnData.length > 0) {
            assembly {
                let returnData_size := mload(returnData)
                revert(add(32, returnData), returnData_size)
            }
        } else {
            revert(error);
        }
    }
}

File 8 of 15 : UintUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title utility functions for uint256 operations
 * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license)
 */
library UintUtils {
    error UintUtils__InsufficientHexLength();

    bytes16 private constant HEX_SYMBOLS = '0123456789abcdef';

    function add(uint256 a, int256 b) internal pure returns (uint256) {
        return b < 0 ? sub(a, -b) : a + uint256(b);
    }

    function sub(uint256 a, int256 b) internal pure returns (uint256) {
        return b < 0 ? add(a, -b) : a - uint256(b);
    }

    function toString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0';
        }

        uint256 temp = value;
        uint256 digits;

        while (temp != 0) {
            digits++;
            temp /= 10;
        }

        bytes memory buffer = new bytes(digits);

        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }

        return string(buffer);
    }

    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return '0x00';
        }

        uint256 length = 0;

        for (uint256 temp = value; temp != 0; temp >>= 8) {
            unchecked {
                length++;
            }
        }

        return toHexString(value, length);
    }

    function toHexString(
        uint256 value,
        uint256 length
    ) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = '0';
        buffer[1] = 'x';

        unchecked {
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = HEX_SYMBOLS[value & 0xf];
                value >>= 4;
            }
        }

        if (value != 0) revert UintUtils__InsufficientHexLength();

        return string(buffer);
    }
}

File 9 of 15 : IChild.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

/**
 * @title ERC-721 Non-Fungible Token Standard, optional child extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 *
 * A child token does not store it's own token balances and does not support
 * minting, transfer, approval. All view methods are passed along to the
 * parent contract.
 */
interface IChild {
    error ERC721Child__InvalidCaller();
    error ERC721Child__NonExistentToken();
    error ERC721Child__ApprovalNotSupported();
    error ERC721Child__TransferNotSupported();

    /**
     * @dev Returns the parent collection.
     */
    function parent() external view returns (address);

    /**
     * @dev Initialize token ownership by calling it from the parent contract.
     *
     * Only call this once in case the child contract after the parent contract.
     * Emits a {Transfer} event from ZeroAddress to current owner per token.
     */
    function init(uint256 tokenIdStart, uint256 tokenIdEnd) external;

    /**
     * @dev Update token ownership from by calling it from the parent contract.
     *
     * Emits a {Transfer} event.
     */
    function update(
        address from,
        address to,
        uint256 tokenId
    ) external;
}

File 10 of 15 : ERC721MarketplaceInternal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import {IERC721MarketplaceInternal} from "./IERC721MarketplaceInternal.sol";
import {ScapesMarketplaceStorage} from "./ScapesMarketplaceStorage.sol";
import {ERC721BaseInternal} from "../solidstate/ERC721BaseInternal.sol";

/// @title ERC721MarketplaceInternal
/// @author akuti.eth, jalil.eth | scapes.eth
/// @dev The internal logic of the ERC721Marketplace.
abstract contract ERC721MarketplaceInternal is
    IERC721MarketplaceInternal,
    ERC721BaseInternal
{
    /// @dev Make a new offer. Emits an {OfferCreated} event.
    function _makeOffer(
        uint256 tokenId,
        uint80 price,
        address to
    ) internal {
        if (price == 0) revert ERC721Marketplace__InvalidPrice();
        if (!_isApprovedOrOwner(msg.sender, tokenId))
            revert ERC721Base__NotOwnerOrApproved();
        ScapesMarketplaceStorage.Offer storage offer = ScapesMarketplaceStorage
            .layout()
            .offers[tokenId];

        offer.price = price;
        offer.specificBuyer = to;

        emit OfferCreated(tokenId, price, to);
    }

    /// @dev Revoke an active offer. Emits an {OfferWithdrawn} event.
    function _cancelOffer(uint256 tokenId) internal {
        ScapesMarketplaceStorage.Offer storage offer = ScapesMarketplaceStorage
            .layout()
            .offers[tokenId];
        if (offer.price == 0) revert ERC721Marketplace__NonExistentOffer();
        offer.price = 0;
        offer.specificBuyer = address(0);
        emit OfferWithdrawn(tokenId);
    }
}

File 11 of 15 : IERC721MarketplaceInternal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import {IERC721BaseInternal} from "@solidstate/contracts/token/ERC721/base/IERC721BaseInternal.sol";

interface IERC721MarketplaceInternal is IERC721BaseInternal {
    error ERC721Marketplace__NonExistentOffer();
    error ERC721Marketplace__InvalidArguments();
    error ERC721Marketplace__PaymentFailed();
    error ERC721Marketplace__InvalidValue();
    error ERC721Marketplace__InvalidPrice();

    event OfferCreated(
        uint256 indexed tokenId,
        uint256 indexed value,
        address indexed to
    );
    event OfferWithdrawn(uint256 indexed tokenId);
    event Sale(
        uint256 indexed tokenId,
        address indexed from,
        address indexed to,
        uint256 value
    );
}

File 12 of 15 : ScapesMarketplaceStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

library ScapesMarketplaceStorage {
    bytes32 internal constant STORAGE_SLOT =
        keccak256("scapes.storage.Marketplace");

    struct Offer {
        uint80 price;
        uint80 specificBuyerPrice;
        uint80 lastPrice;
        address specificBuyer;
    }

    struct Layout {
        address beneficiary;
        uint256 bps;
        mapping(uint256 => Offer) offers;
    }

    function layout() internal pure returns (Layout storage d) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            d.slot := slot
        }
    }
}

File 13 of 15 : ScapesERC721MetadataStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

library ScapesERC721MetadataStorage {
    bytes32 internal constant STORAGE_SLOT =
        keccak256("scapes.storage.ERC721Metadata");

    struct Layout {
        string name;
        string symbol;
        string description;
        string externalBaseURI;
        address scapeBound;
    }

    function layout() internal pure returns (Layout storage d) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            d.slot := slot
        }
    }
}

File 14 of 15 : ERC721BaseInternal.sol
// SPDX-License-Identifier: MIT
// Based on solidstate @solidstate/contracts/token/ERC721/base/ERC721BaseInternal.sol
// Changes made:
//  - store a holder balance instead of the individual tokens, this removes the
//    option to easily upgrade to ERC721Enumerable but lowers gas cost by ~45k per mint
//  - update balance in mint, transfer and burn functions separate balance for normal
//    tokens and merged tokens
//  - update balanceOf to return the combined balance
//  - add _afterTokenTransfer hook

pragma solidity ^0.8.8;

import {IERC721Receiver} from "@solidstate/contracts/interfaces/IERC721Receiver.sol";
import {EnumerableMap} from "@solidstate/contracts/data/EnumerableMap.sol";
import {EnumerableSet} from "@solidstate/contracts/data/EnumerableSet.sol";
import {AddressUtils} from "@solidstate/contracts/utils/AddressUtils.sol";
import {IERC721BaseInternal} from "@solidstate/contracts/token/ERC721/base/IERC721BaseInternal.sol";
import {ERC721BaseStorage} from "./ERC721BaseStorage.sol";

/**
 * @title Base ERC721 internal functions
 */
abstract contract ERC721BaseInternal is IERC721BaseInternal {
    using ERC721BaseStorage for ERC721BaseStorage.Layout;
    using AddressUtils for address;
    using EnumerableMap for EnumerableMap.UintToAddressMap;
    using EnumerableSet for EnumerableSet.UintSet;

    uint256 internal constant MERGES_TRESHOLD = 130_000;

    function _balanceOf(address account)
        internal
        view
        virtual
        returns (uint256)
    {
        if (account == address(0)) revert ERC721Base__BalanceQueryZeroAddress();
        return ERC721BaseStorage.layout().holderBalances[account];
    }

    function _balanceOfMerges(address account)
        internal
        view
        virtual
        returns (uint256)
    {
        if (account == address(0)) revert ERC721Base__BalanceQueryZeroAddress();
        return ERC721BaseStorage.layout().holderBalancesMerges[account];
    }

    function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
        address owner = ERC721BaseStorage.layout().tokenOwners.get(tokenId);
        if (owner == address(0)) revert ERC721Base__InvalidOwner();
        return owner;
    }

    function _getApproved(uint256 tokenId)
        internal
        view
        virtual
        returns (address)
    {
        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();

        if (!l.exists(tokenId)) revert ERC721Base__NonExistentToken();

        return l.tokenApprovals[tokenId];
    }

    function _isApprovedForAll(address account, address operator)
        internal
        view
        virtual
        returns (bool)
    {
        return ERC721BaseStorage.layout().operatorApprovals[account][operator];
    }

    function _isApprovedOrOwner(address spender, uint256 tokenId)
        internal
        view
        virtual
        returns (bool)
    {
        if (!ERC721BaseStorage.layout().exists(tokenId))
            revert ERC721Base__NonExistentToken();

        address owner = _ownerOf(tokenId);

        return (spender == owner ||
            _getApproved(tokenId) == spender ||
            _isApprovedForAll(owner, spender));
    }

    function _mint(address to, uint256 tokenId) internal virtual {
        if (to == address(0)) revert ERC721Base__MintToZeroAddress();

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();

        if (l.exists(tokenId)) revert ERC721Base__TokenAlreadyMinted();

        _beforeTokenTransfer(address(0), to, tokenId);
        unchecked {
            if (tokenId > MERGES_TRESHOLD) l.holderBalancesMerges[to] += 1;
            else l.holderBalances[to] += 1;
        }
        l.tokenOwners.set(tokenId, to);

        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId);
    }

    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _mint(to, tokenId);
        if (!_checkOnERC721Received(address(0), to, tokenId, data))
            revert ERC721Base__ERC721ReceiverNotImplemented();
    }

    function _burn(uint256 tokenId) internal virtual {
        address owner = _ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        _approve(address(0), tokenId);

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
        unchecked {
            if (tokenId > MERGES_TRESHOLD) l.holderBalancesMerges[owner] -= 1;
            else l.holderBalances[owner] -= 1;
        }
        l.tokenOwners.remove(tokenId);

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId);
    }

    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        if (_ownerOf(tokenId) != from) revert ERC721Base__NotTokenOwner();
        if (to == address(0)) revert ERC721Base__TransferToZeroAddress();

        _beforeTokenTransfer(from, to, tokenId);

        _approve(address(0), tokenId);

        ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout();
        unchecked {
            if (tokenId > MERGES_TRESHOLD) {
                l.holderBalancesMerges[from] -= 1;
                l.holderBalancesMerges[to] += 1;
            } else {
                l.holderBalances[from] -= 1;
                l.holderBalances[to] += 1;
            }
        }
        l.tokenOwners.set(tokenId, to);

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _transfer(from, to, tokenId);
        if (!_checkOnERC721Received(from, to, tokenId, data))
            revert ERC721Base__ERC721ReceiverNotImplemented();
    }

    function _approve(address operator, uint256 tokenId) internal virtual {
        ERC721BaseStorage.layout().tokenApprovals[tokenId] = operator;
        emit Approval(_ownerOf(tokenId), operator, tokenId);
    }

    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual returns (bool) {
        if (!to.isContract()) {
            return true;
        }

        bytes memory returnData = to.functionCall(
            abi.encodeWithSelector(
                IERC721Receiver(to).onERC721Received.selector,
                msg.sender,
                from,
                tokenId,
                data
            ),
            "ERC721: transfer to non ERC721Receiver implementer"
        );

        bytes4 returnValue = abi.decode(returnData, (bytes4));
        return returnValue == type(IERC721Receiver).interfaceId;
    }

    /**
     * @notice ERC721 hook, called before externally called approvals for processing of included message value
     * @param operator beneficiary of approval
     * @param tokenId id of transferred token
     * @param value message value
     */
    function _handleApproveMessageValue(
        address operator,
        uint256 tokenId,
        uint256 value
    ) internal virtual {}

    /**
     * @notice ERC721 hook, called before externally called transfers for processing of included message value
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId id of transferred token
     * @param value message value
     */
    function _handleTransferMessageValue(
        address from,
        address to,
        uint256 tokenId,
        uint256 value
    ) internal virtual {}

    /**
     * @notice ERC721 hook, called before all transfers including mint and burn
     * @dev function should be overridden and new implementation must call super
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId id of transferred token
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}

    /**
     * @notice ERC721 hook, called after all transfers including mint and burn
     * @dev function should be overridden and new implementation must call super
     * @param from sender of token
     * @param to receiver of token
     * @param tokenId id of transferred token
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}

File 15 of 15 : ERC721BaseStorage.sol
// SPDX-License-Identifier: MIT
// Based on solidstate @solidstate/contracts/token/ERC721/base/ERC721BaseStorage.sol
// Changes made:
//  - replace holderTokens with holderBalances, this removes the
//    option to easily upgrade to ERC721Enumerable but lowers gas cost by ~45k per mint
//  - add holderBalancesMerges to separetly track the balance of merged scape tokens

pragma solidity ^0.8.8;

import {EnumerableMap} from "@solidstate/contracts/data/EnumerableMap.sol";

library ERC721BaseStorage {
    using EnumerableMap for EnumerableMap.UintToAddressMap;

    bytes32 internal constant STORAGE_SLOT =
        keccak256("scapes.storage.ERC721Base");

    struct Layout {
        EnumerableMap.UintToAddressMap tokenOwners;
        mapping(address => uint256) holderBalances;
        mapping(address => uint256) holderBalancesMerges;
        mapping(uint256 => address) tokenApprovals;
        mapping(address => mapping(address => bool)) operatorApprovals;
    }

    function layout() internal pure returns (Layout storage l) {
        bytes32 slot = STORAGE_SLOT;
        assembly {
            l.slot := slot
        }
    }

    function exists(Layout storage l, uint256 tokenId)
        internal
        view
        returns (bool)
    {
        return l.tokenOwners.contains(tokenId);
    }

    function totalSupply(Layout storage l) internal view returns (uint256) {
        return l.tokenOwners.length();
    }

    function tokenByIndex(Layout storage l, uint256 index)
        internal
        view
        returns (uint256)
    {
        (uint256 tokenId, ) = l.tokenOwners.at(index);
        return tokenId;
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[],"name":"AddressUtils__NotContract","type":"error"},{"inputs":[],"name":"ERC721Base__BalanceQueryZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Base__ERC721ReceiverNotImplemented","type":"error"},{"inputs":[],"name":"ERC721Base__InvalidOwner","type":"error"},{"inputs":[],"name":"ERC721Base__MintToZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Base__NonExistentToken","type":"error"},{"inputs":[],"name":"ERC721Base__NotOwnerOrApproved","type":"error"},{"inputs":[],"name":"ERC721Base__NotTokenOwner","type":"error"},{"inputs":[],"name":"ERC721Base__SelfApproval","type":"error"},{"inputs":[],"name":"ERC721Base__TokenAlreadyMinted","type":"error"},{"inputs":[],"name":"ERC721Base__TransferToZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Marketplace__InvalidArguments","type":"error"},{"inputs":[],"name":"ERC721Marketplace__InvalidPrice","type":"error"},{"inputs":[],"name":"ERC721Marketplace__InvalidValue","type":"error"},{"inputs":[],"name":"ERC721Marketplace__NonExistentOffer","type":"error"},{"inputs":[],"name":"ERC721Marketplace__PaymentFailed","type":"error"},{"inputs":[],"name":"EnumerableMap__NonExistentKey","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OfferCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"OfferWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Sale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchCancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint80[]","name":"prices","type":"uint80[]"}],"name":"batchMakeOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint80[]","name":"prices","type":"uint80[]"},{"internalType":"address[]","name":"tos","type":"address[]"}],"name":"batchMakeOfferTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"cancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getOffer","outputs":[{"components":[{"internalType":"uint80","name":"price","type":"uint80"},{"internalType":"uint80","name":"specificBuyerPrice","type":"uint80"},{"internalType":"uint80","name":"lastPrice","type":"uint80"},{"internalType":"address","name":"specificBuyer","type":"address"}],"internalType":"struct ScapesMarketplaceStorage.Offer","name":"offer","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint80","name":"price","type":"uint80"}],"name":"makeOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint80","name":"price","type":"uint80"},{"internalType":"address","name":"to","type":"address"}],"name":"makeOfferTo","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b506118f7806100206000396000f3fe6080604052600436106100965760003560e01c806383e0de4511610069578063b8c4c4e31161004e578063b8c4c4e31461019c578063d96a094a146101bc578063ef706adf146101cf57600080fd5b806383e0de4514610169578063b03bfd171461017c57600080fd5b80634579268a1461009b5780634d6f011f14610107578063574aec59146101295780635d35ac4d14610149575b600080fd5b3480156100a757600080fd5b506100bb6100b636600461147e565b6101ef565b60408051825169ffffffffffffffffffff90811682526020808501518216908301528383015116818301526060928301516001600160a01b031692810192909252519081900360800190f35b34801561011357600080fd5b506101276101223660046114b6565b6102dc565b005b34801561013557600080fd5b506101276101443660046114f9565b6102ec565b34801561015557600080fd5b50610127610164366004611581565b6102fc565b61012761017736600461161b565b6103b6565b34801561018857600080fd5b5061012761019736600461165d565b6104f1565b3480156101a857600080fd5b506101276101b736600461161b565b610577565b6101276101ca36600461147e565b6105b2565b3480156101db57600080fd5b506101276101ea36600461147e565b61067d565b60408051608080820183526000808352602080840182905283850182905260609384018290528582527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba815284822085519384018652805469ffffffffffffffffffff8082168087526a01000000000000000000008304821694870194909452600160a01b90910416958401959095526001909401546001600160a01b031692820192909252917fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db891036102d657604051630f11ed4560e21b815260040160405180910390fd5b50919050565b6102e8828260006106b0565b5050565b6102f78383836106b0565b505050565b848314158061030b5750848114155b156103295760405163792d3a7360e01b815260040160405180910390fd5b8460005b818110156103ac576103a488888381811061034a5761034a6116c9565b90506020020135878784818110610363576103636116c9565b905060200201602081019061037891906116df565b86868581811061038a5761038a6116c9565b905060200201602081019061039f91906116fa565b6106b0565b60010161032d565b5050505050505050565b7fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8600082815b818110156104c85760008460020160008888858181106103fe576103fe6116c9565b602090810292909201358352508181019290925260409081016000208151608081018352815469ffffffffffffffffffff8082168084526a01000000000000000000008304821696840196909652600160a01b9091041692810192909252600101546001600160a01b03166060820152915061047a908561172b565b93508334101561049d57604051633c976a4360e21b815260040160405180910390fd5b6104bf8787848181106104b2576104b26116c9565b90506020020135826107ca565b506001016103dc565b50813411156104ea57604051633c976a4360e21b815260040160405180910390fd5b5050505050565b8281146105115760405163792d3a7360e01b815260040160405180910390fd5b8260005b8181101561056f57610567868683818110610532576105326116c9565b9050602002013585858481811061054b5761054b6116c9565b905060200201602081019061056091906116df565b60006106b0565b600101610515565b505050505050565b8060005b818110156105ac576105a4848483818110610598576105986116c9565b9050602002013561067d565b60010161057b565b50505050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba60209081526040918290208251608081018452815469ffffffffffffffffffff8082168084526a01000000000000000000008304821695840195909552600160a01b9091041693810193909352600101546001600160a01b03166060830152158015906106555750806000015169ffffffffffffffffffff163414155b1561067357604051633c976a4360e21b815260040160405180910390fd5b6102e882826107ca565b6106873382610ab2565b6106a457604051632f5de44f60e01b815260040160405180910390fd5b6106ad81610b9a565b50565b8169ffffffffffffffffffff166000036106f6576040517f22c25eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107003384610ab2565b61071d57604051632f5de44f60e01b815260040160405180910390fd5b60008381527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040808220805469ffffffffffffffffffff191669ffffffffffffffffffff8616908117825560018201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03871690811790915592519193909187917f1be7385e5a960aabd206224f90e23bb92719f1749fa15a10c0e39302eec9ab5891a450505050565b8051604082015169ffffffffffffffffffff9182169160009116156107ff57826040015169ffffffffffffffffffff16610809565b67016345785d8a00005b90508160000361082c57604051630f11ed4560e21b815260040160405180910390fd5b60608301516001600160a01b031615801590610855575060608301516001600160a01b03163314155b1561087357604051630f11ed4560e21b815260040160405180910390fd5b825169ffffffffffffffffffff163410156108a157604051633c976a4360e21b815260040160405180910390fd5b825160008581527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040902080547fffff00000000000000000000ffffffffffffffffffff0000000000000000000016600160a01b69ffffffffffffffffffff9093169290920269ffffffffffffffffffff191691909117905560608301517fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8906001600160a01b0316156109825760008581526002820160205260409020600101805473ffffffffffffffffffffffffffffffffffffffff191690555b600061098d86610c57565b855190915069ffffffffffffffffffff16831015610a3757600082600101546127106109b9919061173e565b6109c585612710611751565b6109cf9190611770565b905060008186106109fc576127108460010154876109ed9190611751565b6109f79190611770565b610a06565b610a06858761173e565b9050610a1b83610a16838961173e565b610cc6565b8354610a30906001600160a01b031682610cc6565b5050610a41565b610a418134610cc6565b610a5c81338860405180602001604052806000815250610d57565b336001600160a01b0316816001600160a01b0316877f88863d5e20f64464b554931394e2e4b6f09c10015147215bf26b3ba5070acebe87604051610aa291815260200190565b60405180910390a4505050505050565b6000610ade7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff583610da4565b610afb5760405163c1b843ef60e01b815260040160405180910390fd5b6000610b0683610c57565b9050806001600160a01b0316846001600160a01b03161480610b415750836001600160a01b0316610b3684610db7565b6001600160a01b0316145b80610b9057506001600160a01b0380821660009081527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bffa602090815260408083209388168352929052205460ff165b9150505b92915050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba602052604081208054909169ffffffffffffffffffff9091169003610bf857604051630f11ed4560e21b815260040160405180910390fd5b805469ffffffffffffffffffff1916815560018101805473ffffffffffffffffffffffffffffffffffffffff1916905560405182907facbc44b7f46dc350c99fc0d9e5f61ed5c588cb4cdc6b69ea0deb0c5b28e5efc490600090a25050565b600080610c847f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff584610e1e565b90506001600160a01b038116610b94576040517f7e1a7d8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b0316610bb883604051600060405180830381858888f193505050503d8060008114610d17576040519150601f19603f3d011682016040523d82523d6000602084013e610d1c565b606091505b50509050806102f7576040517fe4415dce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d62848484610e2a565b610d6e84848484610fb4565b6105ac576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610db083836110e1565b9392505050565b60007f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff5610de48184610da4565b610e015760405163c1b843ef60e01b815260040160405180910390fd5b60009283526004016020525060409020546001600160a01b031690565b6000610db083836110f9565b826001600160a01b0316610e3d82610c57565b6001600160a01b031614610e7d576040517f0f2db4ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216610ebd576040517f40311a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec8600082611176565b7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff56201fbd0821115610f2a576001600160a01b038085166000908152600383016020526040808220805460001901905591851681522080546001019055610f5c565b6001600160a01b0380851660009081526002830160205260408082208054600019019055918516815220805460010190555b610f67818385611210565b5081836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46105ac848484611226565b60006001600160a01b0384163b610fcd575060016110d9565b600061107863150b7a0260e01b33888787604051602401610ff194939291906117e2565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001611890603291396001600160a01b03881691906112d7565b9050600081806020019051810190611090919061181e565b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a020000000000000000000000000000000000000000000000000000000014925050505b949350505050565b60008181526001830160205260408120541515610db0565b6000818152600183016020526040812054808203611143576040517ff551fb1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600001600182038154811061115b5761115b6116c9565b90600052602060002090600202016001015491505092915050565b60008181527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff960205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03841690811790915581906111d782610c57565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006110d984846001600160a01b0385166112e6565b7f4ca5b6536be965df5a6498d1883a57f2ca8946e5bd14e05eafa6e36d0ceffcd16004908101546040517f8ce516da0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811693820193909352848316602482015260448101849052911690638ce516da90606401600060405180830381600087803b1580156112ba57600080fd5b505af11580156112ce573d6000803e3d6000fd5b50505050505050565b60606110d98484600085611385565b600082815260018401602052604081205480820361134d575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055610db0565b82856000016001830381548110611366576113666116c9565b9060005260206000209060020201600101819055506000915050610db0565b6060843b6113bf576040517f89c35afc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b031685876040516113db9190611860565b60006040518083038185875af1925050503d8060008114611418576040519150601f19603f3d011682016040523d82523d6000602084013e61141d565b606091505b509150915081156114315791506110d99050565b8051156114415780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611475919061187c565b60405180910390fd5b60006020828403121561149057600080fd5b5035919050565b803569ffffffffffffffffffff811681146114b157600080fd5b919050565b600080604083850312156114c957600080fd5b823591506114d960208401611497565b90509250929050565b80356001600160a01b03811681146114b157600080fd5b60008060006060848603121561150e57600080fd5b8335925061151e60208501611497565b915061152c604085016114e2565b90509250925092565b60008083601f84011261154757600080fd5b50813567ffffffffffffffff81111561155f57600080fd5b6020830191508360208260051b850101111561157a57600080fd5b9250929050565b6000806000806000806060878903121561159a57600080fd5b863567ffffffffffffffff808211156115b257600080fd5b6115be8a838b01611535565b909850965060208901359150808211156115d757600080fd5b6115e38a838b01611535565b909650945060408901359150808211156115fc57600080fd5b5061160989828a01611535565b979a9699509497509295939492505050565b6000806020838503121561162e57600080fd5b823567ffffffffffffffff81111561164557600080fd5b61165185828601611535565b90969095509350505050565b6000806000806040858703121561167357600080fd5b843567ffffffffffffffff8082111561168b57600080fd5b61169788838901611535565b909650945060208701359150808211156116b057600080fd5b506116bd87828801611535565b95989497509550505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156116f157600080fd5b610db082611497565b60006020828403121561170c57600080fd5b610db0826114e2565b634e487b7160e01b600052601160045260246000fd5b80820180821115610b9457610b94611715565b81810381811115610b9457610b94611715565b600081600019048311821515161561176b5761176b611715565b500290565b60008261178d57634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156117ad578181015183820152602001611795565b50506000910152565b600081518084526117ce816020860160208601611792565b601f01601f19169290920160200192915050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261181460808301846117b6565b9695505050505050565b60006020828403121561183057600080fd5b81517fffffffff0000000000000000000000000000000000000000000000000000000081168114610db057600080fd5b60008251611872818460208701611792565b9190910192915050565b602081526000610db060208301846117b656fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a2646970667358221220f7420dd88d408d7cea7b261db4f2e96bc1649c669d63951732df77385ff346bc64736f6c63430008100033

Deployed Bytecode

0x6080604052600436106100965760003560e01c806383e0de4511610069578063b8c4c4e31161004e578063b8c4c4e31461019c578063d96a094a146101bc578063ef706adf146101cf57600080fd5b806383e0de4514610169578063b03bfd171461017c57600080fd5b80634579268a1461009b5780634d6f011f14610107578063574aec59146101295780635d35ac4d14610149575b600080fd5b3480156100a757600080fd5b506100bb6100b636600461147e565b6101ef565b60408051825169ffffffffffffffffffff90811682526020808501518216908301528383015116818301526060928301516001600160a01b031692810192909252519081900360800190f35b34801561011357600080fd5b506101276101223660046114b6565b6102dc565b005b34801561013557600080fd5b506101276101443660046114f9565b6102ec565b34801561015557600080fd5b50610127610164366004611581565b6102fc565b61012761017736600461161b565b6103b6565b34801561018857600080fd5b5061012761019736600461165d565b6104f1565b3480156101a857600080fd5b506101276101b736600461161b565b610577565b6101276101ca36600461147e565b6105b2565b3480156101db57600080fd5b506101276101ea36600461147e565b61067d565b60408051608080820183526000808352602080840182905283850182905260609384018290528582527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba815284822085519384018652805469ffffffffffffffffffff8082168087526a01000000000000000000008304821694870194909452600160a01b90910416958401959095526001909401546001600160a01b031692820192909252917fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db891036102d657604051630f11ed4560e21b815260040160405180910390fd5b50919050565b6102e8828260006106b0565b5050565b6102f78383836106b0565b505050565b848314158061030b5750848114155b156103295760405163792d3a7360e01b815260040160405180910390fd5b8460005b818110156103ac576103a488888381811061034a5761034a6116c9565b90506020020135878784818110610363576103636116c9565b905060200201602081019061037891906116df565b86868581811061038a5761038a6116c9565b905060200201602081019061039f91906116fa565b6106b0565b60010161032d565b5050505050505050565b7fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8600082815b818110156104c85760008460020160008888858181106103fe576103fe6116c9565b602090810292909201358352508181019290925260409081016000208151608081018352815469ffffffffffffffffffff8082168084526a01000000000000000000008304821696840196909652600160a01b9091041692810192909252600101546001600160a01b03166060820152915061047a908561172b565b93508334101561049d57604051633c976a4360e21b815260040160405180910390fd5b6104bf8787848181106104b2576104b26116c9565b90506020020135826107ca565b506001016103dc565b50813411156104ea57604051633c976a4360e21b815260040160405180910390fd5b5050505050565b8281146105115760405163792d3a7360e01b815260040160405180910390fd5b8260005b8181101561056f57610567868683818110610532576105326116c9565b9050602002013585858481811061054b5761054b6116c9565b905060200201602081019061056091906116df565b60006106b0565b600101610515565b505050505050565b8060005b818110156105ac576105a4848483818110610598576105986116c9565b9050602002013561067d565b60010161057b565b50505050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba60209081526040918290208251608081018452815469ffffffffffffffffffff8082168084526a01000000000000000000008304821695840195909552600160a01b9091041693810193909352600101546001600160a01b03166060830152158015906106555750806000015169ffffffffffffffffffff163414155b1561067357604051633c976a4360e21b815260040160405180910390fd5b6102e882826107ca565b6106873382610ab2565b6106a457604051632f5de44f60e01b815260040160405180910390fd5b6106ad81610b9a565b50565b8169ffffffffffffffffffff166000036106f6576040517f22c25eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107003384610ab2565b61071d57604051632f5de44f60e01b815260040160405180910390fd5b60008381527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040808220805469ffffffffffffffffffff191669ffffffffffffffffffff8616908117825560018201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03871690811790915592519193909187917f1be7385e5a960aabd206224f90e23bb92719f1749fa15a10c0e39302eec9ab5891a450505050565b8051604082015169ffffffffffffffffffff9182169160009116156107ff57826040015169ffffffffffffffffffff16610809565b67016345785d8a00005b90508160000361082c57604051630f11ed4560e21b815260040160405180910390fd5b60608301516001600160a01b031615801590610855575060608301516001600160a01b03163314155b1561087357604051630f11ed4560e21b815260040160405180910390fd5b825169ffffffffffffffffffff163410156108a157604051633c976a4360e21b815260040160405180910390fd5b825160008581527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040902080547fffff00000000000000000000ffffffffffffffffffff0000000000000000000016600160a01b69ffffffffffffffffffff9093169290920269ffffffffffffffffffff191691909117905560608301517fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8906001600160a01b0316156109825760008581526002820160205260409020600101805473ffffffffffffffffffffffffffffffffffffffff191690555b600061098d86610c57565b855190915069ffffffffffffffffffff16831015610a3757600082600101546127106109b9919061173e565b6109c585612710611751565b6109cf9190611770565b905060008186106109fc576127108460010154876109ed9190611751565b6109f79190611770565b610a06565b610a06858761173e565b9050610a1b83610a16838961173e565b610cc6565b8354610a30906001600160a01b031682610cc6565b5050610a41565b610a418134610cc6565b610a5c81338860405180602001604052806000815250610d57565b336001600160a01b0316816001600160a01b0316877f88863d5e20f64464b554931394e2e4b6f09c10015147215bf26b3ba5070acebe87604051610aa291815260200190565b60405180910390a4505050505050565b6000610ade7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff583610da4565b610afb5760405163c1b843ef60e01b815260040160405180910390fd5b6000610b0683610c57565b9050806001600160a01b0316846001600160a01b03161480610b415750836001600160a01b0316610b3684610db7565b6001600160a01b0316145b80610b9057506001600160a01b0380821660009081527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bffa602090815260408083209388168352929052205460ff165b9150505b92915050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba602052604081208054909169ffffffffffffffffffff9091169003610bf857604051630f11ed4560e21b815260040160405180910390fd5b805469ffffffffffffffffffff1916815560018101805473ffffffffffffffffffffffffffffffffffffffff1916905560405182907facbc44b7f46dc350c99fc0d9e5f61ed5c588cb4cdc6b69ea0deb0c5b28e5efc490600090a25050565b600080610c847f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff584610e1e565b90506001600160a01b038116610b94576040517f7e1a7d8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b0316610bb883604051600060405180830381858888f193505050503d8060008114610d17576040519150601f19603f3d011682016040523d82523d6000602084013e610d1c565b606091505b50509050806102f7576040517fe4415dce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d62848484610e2a565b610d6e84848484610fb4565b6105ac576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610db083836110e1565b9392505050565b60007f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff5610de48184610da4565b610e015760405163c1b843ef60e01b815260040160405180910390fd5b60009283526004016020525060409020546001600160a01b031690565b6000610db083836110f9565b826001600160a01b0316610e3d82610c57565b6001600160a01b031614610e7d576040517f0f2db4ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216610ebd576040517f40311a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec8600082611176565b7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff56201fbd0821115610f2a576001600160a01b038085166000908152600383016020526040808220805460001901905591851681522080546001019055610f5c565b6001600160a01b0380851660009081526002830160205260408082208054600019019055918516815220805460010190555b610f67818385611210565b5081836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46105ac848484611226565b60006001600160a01b0384163b610fcd575060016110d9565b600061107863150b7a0260e01b33888787604051602401610ff194939291906117e2565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001611890603291396001600160a01b03881691906112d7565b9050600081806020019051810190611090919061181e565b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a020000000000000000000000000000000000000000000000000000000014925050505b949350505050565b60008181526001830160205260408120541515610db0565b6000818152600183016020526040812054808203611143576040517ff551fb1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600001600182038154811061115b5761115b6116c9565b90600052602060002090600202016001015491505092915050565b60008181527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff960205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03841690811790915581906111d782610c57565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006110d984846001600160a01b0385166112e6565b7f4ca5b6536be965df5a6498d1883a57f2ca8946e5bd14e05eafa6e36d0ceffcd16004908101546040517f8ce516da0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811693820193909352848316602482015260448101849052911690638ce516da90606401600060405180830381600087803b1580156112ba57600080fd5b505af11580156112ce573d6000803e3d6000fd5b50505050505050565b60606110d98484600085611385565b600082815260018401602052604081205480820361134d575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055610db0565b82856000016001830381548110611366576113666116c9565b9060005260206000209060020201600101819055506000915050610db0565b6060843b6113bf576040517f89c35afc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b031685876040516113db9190611860565b60006040518083038185875af1925050503d8060008114611418576040519150601f19603f3d011682016040523d82523d6000602084013e61141d565b606091505b509150915081156114315791506110d99050565b8051156114415780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611475919061187c565b60405180910390fd5b60006020828403121561149057600080fd5b5035919050565b803569ffffffffffffffffffff811681146114b157600080fd5b919050565b600080604083850312156114c957600080fd5b823591506114d960208401611497565b90509250929050565b80356001600160a01b03811681146114b157600080fd5b60008060006060848603121561150e57600080fd5b8335925061151e60208501611497565b915061152c604085016114e2565b90509250925092565b60008083601f84011261154757600080fd5b50813567ffffffffffffffff81111561155f57600080fd5b6020830191508360208260051b850101111561157a57600080fd5b9250929050565b6000806000806000806060878903121561159a57600080fd5b863567ffffffffffffffff808211156115b257600080fd5b6115be8a838b01611535565b909850965060208901359150808211156115d757600080fd5b6115e38a838b01611535565b909650945060408901359150808211156115fc57600080fd5b5061160989828a01611535565b979a9699509497509295939492505050565b6000806020838503121561162e57600080fd5b823567ffffffffffffffff81111561164557600080fd5b61165185828601611535565b90969095509350505050565b6000806000806040858703121561167357600080fd5b843567ffffffffffffffff8082111561168b57600080fd5b61169788838901611535565b909650945060208701359150808211156116b057600080fd5b506116bd87828801611535565b95989497509550505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156116f157600080fd5b610db082611497565b60006020828403121561170c57600080fd5b610db0826114e2565b634e487b7160e01b600052601160045260246000fd5b80820180821115610b9457610b94611715565b81810381811115610b9457610b94611715565b600081600019048311821515161561176b5761176b611715565b500290565b60008261178d57634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156117ad578181015183820152602001611795565b50506000910152565b600081518084526117ce816020860160208601611792565b601f01601f19169290920160200192915050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261181460808301846117b6565b9695505050505050565b60006020828403121561183057600080fd5b81517fffffffff0000000000000000000000000000000000000000000000000000000081168114610db057600080fd5b60008251611872818460208701611792565b9190910192915050565b602081526000610db060208301846117b656fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a2646970667358221220f7420dd88d408d7cea7b261db4f2e96bc1649c669d63951732df77385ff346bc64736f6c63430008100033

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.