ETH Price: $3,333.73 (-1.49%)
Gas: 24 Gwei

Contract

0x0e720B468737664Ec57bb545F798F71bC57605c1
 

Overview

ETH Balance

0.0455475 ETH

Eth Value

$151.84 (@ $3,333.73/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Delist Ethscript...192453392024-02-17 4:54:59164 days ago1708145699IN
0x0e720B46...bC57605c1
0 ETH0.0005689615.38564601
List Ethscriptio...192239692024-02-14 4:56:35167 days ago1707886595IN
0x0e720B46...bC57605c1
0 ETH0.0017290114.62363444
0xaa356477192239652024-02-14 4:55:47167 days ago1707886547IN
0x0e720B46...bC57605c1
0 ETH0.0010474416.89367747
Withdraw Ethscri...192187942024-02-13 11:28:23167 days ago1707823703IN
0x0e720B46...bC57605c1
0 ETH0.0009414823.91987561
List Ethscriptio...192106982024-02-12 8:17:11169 days ago1707725831IN
0x0e720B46...bC57605c1
0 ETH0.0022370418.92244603
0x2809f113192106962024-02-12 8:16:47169 days ago1707725807IN
0x0e720B46...bC57605c1
0 ETH0.001311421.150622
Delist Ethscript...191812362024-02-08 5:03:23173 days ago1707368603IN
0x0e720B46...bC57605c1
0 ETH0.0013186935.65974115
List Ethscriptio...191809642024-02-08 4:08:11173 days ago1707365291IN
0x0e720B46...bC57605c1
0 ETH0.0036449130.82795601
0x485c8f3d191809592024-02-08 4:07:11173 days ago1707365231IN
0x0e720B46...bC57605c1
0 ETH0.0018121329.22649634
List Ethscriptio...191809052024-02-08 3:56:11173 days ago1707364571IN
0x0e720B46...bC57605c1
0 ETH0.0032333427.34980561
0x9be0146e191809032024-02-08 3:55:47173 days ago1707364547IN
0x0e720B46...bC57605c1
0 ETH0.001728727.88141513
Buy Ethscription191728772024-02-07 0:52:35174 days ago1707267155IN
0x0e720B46...bC57605c1
0.0069 ETH0.0014938825.23915448
List Ethscriptio...191715912024-02-06 20:32:23174 days ago1707251543IN
0x0e720B46...bC57605c1
0 ETH0.0040150533.96197298
0xaec2eeea191715812024-02-06 20:30:23174 days ago1707251423IN
0x0e720B46...bC57605c1
0 ETH0.0018012229.05100044
Withdraw Ethscri...191579492024-02-04 22:36:11176 days ago1707086171IN
0x0e720B46...bC57605c1
0 ETH0.0006384916.22182112
List Ethscriptio...191540222024-02-04 9:21:35177 days ago1707038495IN
0x0e720B46...bC57605c1
0 ETH0.0020256417.13420782
0xa1e8fd1d191540202024-02-04 9:21:11177 days ago1707038471IN
0x0e720B46...bC57605c1
0 ETH0.0011136917.96222807
Delist Ethscript...191392732024-02-02 7:36:47179 days ago1706859407IN
0x0e720B46...bC57605c1
0 ETH0.0008126621.97576669
List Ethscriptio...191392022024-02-02 7:22:35179 days ago1706858555IN
0x0e720B46...bC57605c1
0 ETH0.0024577820.78957802
0xf33e8e64191391802024-02-02 7:18:11179 days ago1706858291IN
0x0e720B46...bC57605c1
0 ETH0.0011152717.98801939
List Ethscriptio...191339502024-02-01 13:42:47179 days ago1706794967IN
0x0e720B46...bC57605c1
0 ETH0.0031703826.81725864
0xe67d4377191339472024-02-01 13:42:11179 days ago1706794931IN
0x0e720B46...bC57605c1
0 ETH0.0017221327.77594601
Buy Ethscription191311592024-02-01 4:17:23180 days ago1706761043IN
0x0e720B46...bC57605c1
0.28 ETH0.0011848720.01505958
0x8de49a92191298582024-01-31 23:53:47180 days ago1706745227IN
0x0e720B46...bC57605c1
0 ETH0.0013111121.14626271
List Ethscriptio...191298292024-01-31 23:47:59180 days ago1706744879IN
0x0e720B46...bC57605c1
0 ETH0.0026607322.50624209
View all transactions

Latest 15 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
191728772024-02-07 0:52:35174 days ago1707267155
0x0e720B46...bC57605c1
0.0067275 ETH
191311592024-02-01 4:17:23180 days ago1706761043
0x0e720B46...bC57605c1
0.273 ETH
191026992024-01-28 4:36:59184 days ago1706416619
0x0e720B46...bC57605c1
0.067275 ETH
190940802024-01-26 23:34:35185 days ago1706312075
0x0e720B46...bC57605c1
0.032175 ETH
190313912024-01-18 4:33:35194 days ago1705552415
0x0e720B46...bC57605c1
0.24375 ETH
189947832024-01-13 1:46:35199 days ago1705110395
0x0e720B46...bC57605c1
0.119925 ETH
189885402024-01-12 4:49:47200 days ago1705034987
0x0e720B46...bC57605c1
0.24375 ETH
189884062024-01-12 4:22:23200 days ago1705033343
0x0e720B46...bC57605c1
0.14625 ETH
189816512024-01-11 5:36:47201 days ago1704951407
0x0e720B46...bC57605c1
0.234 ETH
189814782024-01-11 5:01:47201 days ago1704949307
0x0e720B46...bC57605c1
0.0975 ETH
189813812024-01-11 4:42:23201 days ago1704948143
0x0e720B46...bC57605c1
0.0975 ETH
189813622024-01-11 4:38:35201 days ago1704947915
0x0e720B46...bC57605c1
0.067275 ETH
189808482024-01-11 2:54:35201 days ago1704941675
0x0e720B46...bC57605c1
0.0975 ETH
189807812024-01-11 2:40:59201 days ago1704940859
0x0e720B46...bC57605c1
0.000975 ETH
189753342024-01-10 8:23:35202 days ago1704875015
0x0e720B46...bC57605c1
0.04875 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
MemeScribeMarket

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
No with 200 runs

Other Settings:
paris EvmVersion
File 1 of 17 : MemeScribeMarket.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.17;
import "@solidstate/contracts/security/reentrancy_guard/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "solady/src/utils/SafeTransferLib.sol";
import "solady/src/utils/ECDSA.sol";
import "solady/src/utils/ERC1967FactoryConstants.sol";
import "./EthscriptionsEscrower.sol";

contract MemeScribeMarket is ReentrancyGuard, EthscriptionsEscrower, Ownable {
    using SafeTransferLib for address;
    using ECDSA for bytes32;

    constructor() Ownable(msg.sender) {
        // Your constructor logic here
    }

    uint public fee = 250; // 2.5%
    uint public constant FEE_DENOMINATOR = 10000;
    uint public feesAccumulated = 0;

    struct Listing {
        bool isForSale;
        bytes32 ethscriptionId;
        address seller;
        uint price;
    }

    mapping(bytes32 => Listing) public ethscriptionsOfferedForSale;

    event EthscriptionListed(
        bytes32 indexed ethscriptionId,
        uint price,
        address indexed seller
    );

    event EthscriptionDelisted(
        bytes32 indexed ethscriptionId,
        address indexed seller
    );

    event EthscriptionPurchased(
        bytes32 indexed ethscriptionId,
        uint price,
        address indexed seller,
        address indexed buyer
    );

    function listEthscription(
        bytes32 ethscriptionId,
        uint price
    ) external nonReentrant {
        _listEthscription(ethscriptionId, price);
    }

    function _listEthscription(bytes32 ethscriptionId, uint price) internal {
        require(
            !userEthscriptionDefinitelyNotStored(msg.sender, ethscriptionId),
            "Sender is not depositor"
        );

        ethscriptionsOfferedForSale[ethscriptionId] = Listing({
            isForSale: true,
            ethscriptionId: ethscriptionId,
            seller: msg.sender,
            price: price
        });

        emit EthscriptionListed(ethscriptionId, price, msg.sender);
    }

    function delistEthscription(bytes32 ethscriptionId) public nonReentrant {
        require(
            !userEthscriptionDefinitelyNotStored(msg.sender, ethscriptionId),
            "Sender is not depositor"
        );

        ethscriptionsOfferedForSale[ethscriptionId] = Listing(
            false,
            ethscriptionId,
            msg.sender,
            0
        );

        emit EthscriptionDelisted(ethscriptionId, msg.sender);
    }

    function batchListEthscriptions(
        bytes32[] memory ethscriptionIds,
        uint[] memory prices
    ) external nonReentrant {
        require(
            ethscriptionIds.length == prices.length,
            "Array lengths do not match"
        );

        for (uint i = 0; i < ethscriptionIds.length; i++) {
            _listEthscription(ethscriptionIds[i], prices[i]);
        }
    }

    function buyEthscription(
        bytes32 ethscriptionId,
        uint price
    ) public payable nonReentrant {
        _buyEthscription(ethscriptionId, price);
    }

    function _buyEthscription(bytes32 ethscriptionId, uint price) internal {
        Listing memory listing = ethscriptionsOfferedForSale[ethscriptionId];

        if (!listing.isForSale) revert("Ethscription is not for sale");

        if (msg.value != listing.price) revert("Not enough ether");

        address seller = listing.seller;

        if (seller == msg.sender) revert("Seller is buyer");

        ethscriptionsOfferedForSale[ethscriptionId] = Listing(
            false,
            ethscriptionId,
            msg.sender,
            0
        );

        _transferEthscription(seller, msg.sender, ethscriptionId);

        // send ether to seller
        uint feeAmount = (listing.price * fee) / FEE_DENOMINATOR;
        uint amountToSendtoSeller = listing.price - feeAmount;
        feesAccumulated += feeAmount;
        payable(seller).transfer(amountToSendtoSeller);

        emit EthscriptionPurchased(
            ethscriptionId,
            listing.price,
            seller,
            msg.sender
        );
    }

    function batchBuyEthscription(
        bytes32[] calldata ethscriptionIds,
        uint[] calldata prices
    ) external payable nonReentrant {
        require(
            ethscriptionIds.length == prices.length,
            "Array lengths do not match"
        );

        uint totalSalePrice = 0;
        for (uint i = 0; i < ethscriptionIds.length; i++) {
            _buyEthscription(ethscriptionIds[i], prices[i]);
            totalSalePrice += prices[i];
        }

        require(msg.value == totalSalePrice, "Incorrect total Ether sent");
    }

    function withdrawEthscription(bytes32 ethscriptionId) public override {
        require(
            !userEthscriptionDefinitelyNotStored(msg.sender, ethscriptionId),
            "Sender is not depositor"
        );

        // Withdraw ethscription
        super.withdrawEthscription(ethscriptionId);

        Listing memory listing = ethscriptionsOfferedForSale[ethscriptionId];
        // Check that the offer is valid
        if (listing.isForSale) {
            // Invalidate listing
            _invalidateListing(ethscriptionId);
        }
    }

    function _invalidateListing(bytes32 ethscriptionId) internal {
        ethscriptionsOfferedForSale[ethscriptionId] = Listing(
            false,
            ethscriptionId,
            msg.sender,
            0
        );

        emit EthscriptionDelisted(ethscriptionId, msg.sender);
    }

    // Owner functions
    function setMarketPlaceFee(uint updatedFee) public onlyOwner {
        fee = updatedFee;
    }

    function withdrawFees() public onlyOwner {
        uint amount = feesAccumulated;
        feesAccumulated = 0;
        payable(msg.sender).transfer(amount);
    }

    function transferContractOwner(address newOwner) public onlyOwner {
        transferOwnership(newOwner);
    }

    // Overrides
    function _onPotentialEthscriptionDeposit(
        address previousOwner,
        bytes memory userCallData
    ) internal virtual override {
        require(userCallData.length % 32 == 0, "InvalidEthscriptionLength");

        // Process each ethscriptionId
        for (uint256 i = 0; i < userCallData.length / 32; i++) {
            bytes32 potentialEthscriptionId = abi.decode(
                slice(userCallData, i * 32, 32),
                (bytes32)
            );

            if (
                userEthscriptionPossiblyStored(
                    previousOwner,
                    potentialEthscriptionId
                )
            ) {
                revert EthscriptionAlreadyReceivedFromSender();
            }

            EthscriptionsEscrowerStorage.s().ethscriptionReceivedOnBlockNumber[
                previousOwner
            ][potentialEthscriptionId] = block.number;
        }
    }

    // Utils
    function slice(
        bytes memory data,
        uint256 start,
        uint256 len
    ) internal pure returns (bytes memory) {
        bytes memory b = new bytes(len);
        for (uint256 i = 0; i < len; i++) {
            b[i] = data[i + start];
        }
        return b;
    }

    fallback() external {
        _onPotentialEthscriptionDeposit(msg.sender, msg.data);
    }
}

File 2 of 17 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 17 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 4 of 17 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

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

/**
 * @title ERC20 interface
 * @dev see https://eips.ethereum.org/EIPS/eip-20
 */
interface IERC20 is IERC20Internal {
    /**
     * @notice query the total minted token supply
     * @return token supply
     */
    function totalSupply() external view returns (uint256);

    /**
     * @notice query the token balance of given account
     * @param account address to query
     * @return token balance
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @notice query the allowance granted from given holder to given spender
     * @param holder approver of allowance
     * @param spender recipient of allowance
     * @return token allowance
     */
    function allowance(
        address holder,
        address spender
    ) external view returns (uint256);

    /**
     * @notice grant approval to spender to spend tokens
     * @dev prefer ERC20Extended functions to avoid transaction-ordering vulnerability (see https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729)
     * @param spender recipient of allowance
     * @param amount quantity of tokens approved for spending
     * @return success status (always true; otherwise function should revert)
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @notice transfer tokens to given recipient
     * @param recipient beneficiary of token transfer
     * @param amount quantity of tokens to transfer
     * @return success status (always true; otherwise function should revert)
     */
    function transfer(
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @notice transfer tokens to given recipient on behalf of given holder
     * @param holder holder of tokens prior to transfer
     * @param recipient beneficiary of token transfer
     * @param amount quantity of tokens to transfer
     * @return success status (always true; otherwise function should revert)
     */
    function transferFrom(
        address holder,
        address recipient,
        uint256 amount
    ) external returns (bool);
}

File 5 of 17 : IERC20Internal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

/**
 * @title Partial ERC20 interface needed by internal functions
 */
interface IERC20Internal {
    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );
}

File 6 of 17 : IReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IReentrancyGuard {
    error ReentrancyGuard__ReentrantCall();
}

File 7 of 17 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IReentrancyGuard } from './IReentrancyGuard.sol';
import { ReentrancyGuardStorage } from './ReentrancyGuardStorage.sol';

/**
 * @title Utility contract for preventing reentrancy attacks
 */
abstract contract ReentrancyGuard is IReentrancyGuard {
    uint256 internal constant REENTRANCY_STATUS_LOCKED = 2;
    uint256 internal constant REENTRANCY_STATUS_UNLOCKED = 1;

    modifier nonReentrant() virtual {
        if (_isReentrancyGuardLocked()) revert ReentrancyGuard__ReentrantCall();
        _lockReentrancyGuard();
        _;
        _unlockReentrancyGuard();
    }

    /**
     * @notice returns true if the reentrancy guard is locked, false otherwise
     */
    function _isReentrancyGuardLocked() internal view virtual returns (bool) {
        return
            ReentrancyGuardStorage.layout().status == REENTRANCY_STATUS_LOCKED;
    }

    /**
     * @notice lock functions that use the nonReentrant modifier
     */
    function _lockReentrancyGuard() internal virtual {
        ReentrancyGuardStorage.layout().status = REENTRANCY_STATUS_LOCKED;
    }

    /**
     * @notice unlock functions that use the nonReentrant modifier
     */
    function _unlockReentrancyGuard() internal virtual {
        ReentrancyGuardStorage.layout().status = REENTRANCY_STATUS_UNLOCKED;
    }
}

File 8 of 17 : ReentrancyGuardStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

library ReentrancyGuardStorage {
    struct Layout {
        uint256 status;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ReentrancyGuard');

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

File 9 of 17 : ERC20Base.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC20 } from '../../../interfaces/IERC20.sol';
import { IERC20Base } from './IERC20Base.sol';
import { ERC20BaseInternal } from './ERC20BaseInternal.sol';
import { ERC20BaseStorage } from './ERC20BaseStorage.sol';

/**
 * @title Base ERC20 implementation, excluding optional extensions
 */
abstract contract ERC20Base is IERC20Base, ERC20BaseInternal {
    /**
     * @inheritdoc IERC20
     */
    function totalSupply() external view returns (uint256) {
        return _totalSupply();
    }

    /**
     * @inheritdoc IERC20
     */
    function balanceOf(address account) external view returns (uint256) {
        return _balanceOf(account);
    }

    /**
     * @inheritdoc IERC20
     */
    function allowance(
        address holder,
        address spender
    ) external view returns (uint256) {
        return _allowance(holder, spender);
    }

    /**
     * @inheritdoc IERC20
     */
    function approve(address spender, uint256 amount) external returns (bool) {
        return _approve(msg.sender, spender, amount);
    }

    /**
     * @inheritdoc IERC20
     */
    function transfer(
        address recipient,
        uint256 amount
    ) external returns (bool) {
        return _transfer(msg.sender, recipient, amount);
    }

    /**
     * @inheritdoc IERC20
     */
    function transferFrom(
        address holder,
        address recipient,
        uint256 amount
    ) external returns (bool) {
        return _transferFrom(holder, recipient, amount);
    }
}

File 10 of 17 : ERC20BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC20BaseInternal } from './IERC20BaseInternal.sol';
import { ERC20BaseStorage } from './ERC20BaseStorage.sol';

/**
 * @title Base ERC20 internal functions, excluding optional extensions
 */
abstract contract ERC20BaseInternal is IERC20BaseInternal {
    /**
     * @notice query the total minted token supply
     * @return token supply
     */
    function _totalSupply() internal view virtual returns (uint256) {
        return ERC20BaseStorage.layout().totalSupply;
    }

    /**
     * @notice query the token balance of given account
     * @param account address to query
     * @return token balance
     */
    function _balanceOf(
        address account
    ) internal view virtual returns (uint256) {
        return ERC20BaseStorage.layout().balances[account];
    }

    /**
     * @notice query the allowance granted from given holder to given spender
     * @param holder approver of allowance
     * @param spender recipient of allowance
     * @return token allowance
     */
    function _allowance(
        address holder,
        address spender
    ) internal view virtual returns (uint256) {
        return ERC20BaseStorage.layout().allowances[holder][spender];
    }

    /**
     * @notice enable spender to spend tokens on behalf of holder
     * @param holder address on whose behalf tokens may be spent
     * @param spender recipient of allowance
     * @param amount quantity of tokens approved for spending
     * @return success status (always true; otherwise function should revert)
     */
    function _approve(
        address holder,
        address spender,
        uint256 amount
    ) internal virtual returns (bool) {
        if (holder == address(0)) revert ERC20Base__ApproveFromZeroAddress();
        if (spender == address(0)) revert ERC20Base__ApproveToZeroAddress();

        ERC20BaseStorage.layout().allowances[holder][spender] = amount;

        emit Approval(holder, spender, amount);

        return true;
    }

    /**
     * @notice decrease spend amount granted by holder to spender
     * @param holder address on whose behalf tokens may be spent
     * @param spender address whose allowance to decrease
     * @param amount quantity by which to decrease allowance
     */
    function _decreaseAllowance(
        address holder,
        address spender,
        uint256 amount
    ) internal {
        uint256 allowance = _allowance(holder, spender);

        if (amount > allowance) revert ERC20Base__InsufficientAllowance();

        unchecked {
            _approve(holder, spender, allowance - amount);
        }
    }

    /**
     * @notice mint tokens for given account
     * @param account recipient of minted tokens
     * @param amount quantity of tokens minted
     */
    function _mint(address account, uint256 amount) internal virtual {
        if (account == address(0)) revert ERC20Base__MintToZeroAddress();

        _beforeTokenTransfer(address(0), account, amount);

        ERC20BaseStorage.Layout storage l = ERC20BaseStorage.layout();
        l.totalSupply += amount;
        l.balances[account] += amount;

        emit Transfer(address(0), account, amount);
    }

    /**
     * @notice burn tokens held by given account
     * @param account holder of burned tokens
     * @param amount quantity of tokens burned
     */
    function _burn(address account, uint256 amount) internal virtual {
        if (account == address(0)) revert ERC20Base__BurnFromZeroAddress();

        _beforeTokenTransfer(account, address(0), amount);

        ERC20BaseStorage.Layout storage l = ERC20BaseStorage.layout();
        uint256 balance = l.balances[account];
        if (amount > balance) revert ERC20Base__BurnExceedsBalance();
        unchecked {
            l.balances[account] = balance - amount;
        }
        l.totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    /**
     * @notice transfer tokens from holder to recipient
     * @param holder owner of tokens to be transferred
     * @param recipient beneficiary of transfer
     * @param amount quantity of tokens transferred
     * @return success status (always true; otherwise function should revert)
     */
    function _transfer(
        address holder,
        address recipient,
        uint256 amount
    ) internal virtual returns (bool) {
        if (holder == address(0)) revert ERC20Base__TransferFromZeroAddress();
        if (recipient == address(0)) revert ERC20Base__TransferToZeroAddress();

        _beforeTokenTransfer(holder, recipient, amount);

        ERC20BaseStorage.Layout storage l = ERC20BaseStorage.layout();
        uint256 holderBalance = l.balances[holder];
        if (amount > holderBalance) revert ERC20Base__TransferExceedsBalance();
        unchecked {
            l.balances[holder] = holderBalance - amount;
        }
        l.balances[recipient] += amount;

        emit Transfer(holder, recipient, amount);

        return true;
    }

    /**
     * @notice transfer tokens to given recipient on behalf of given holder
     * @param holder holder of tokens prior to transfer
     * @param recipient beneficiary of token transfer
     * @param amount quantity of tokens to transfer
     * @return success status (always true; otherwise function should revert)
     */
    function _transferFrom(
        address holder,
        address recipient,
        uint256 amount
    ) internal virtual returns (bool) {
        _decreaseAllowance(holder, msg.sender, amount);

        _transfer(holder, recipient, amount);

        return true;
    }

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

File 11 of 17 : ERC20BaseStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

library ERC20BaseStorage {
    struct Layout {
        mapping(address => uint256) balances;
        mapping(address => mapping(address => uint256)) allowances;
        uint256 totalSupply;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256('solidstate.contracts.storage.ERC20Base');

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

File 12 of 17 : IERC20Base.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

import { IERC20 } from '../../../interfaces/IERC20.sol';
import { IERC20BaseInternal } from './IERC20BaseInternal.sol';

/**
 * @title ERC20 base interface
 */
interface IERC20Base is IERC20BaseInternal, IERC20 {

}

File 13 of 17 : IERC20BaseInternal.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.8;

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

/**
 * @title ERC20 base interface
 */
interface IERC20BaseInternal is IERC20Internal {
    error ERC20Base__ApproveFromZeroAddress();
    error ERC20Base__ApproveToZeroAddress();
    error ERC20Base__BurnExceedsBalance();
    error ERC20Base__BurnFromZeroAddress();
    error ERC20Base__InsufficientAllowance();
    error ERC20Base__MintToZeroAddress();
    error ERC20Base__TransferExceedsBalance();
    error ERC20Base__TransferFromZeroAddress();
    error ERC20Base__TransferToZeroAddress();
}

File 14 of 17 : EthscriptionsEscrower.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.20;

import "@solidstate/contracts/token/ERC20/base/ERC20Base.sol";

library EthscriptionsEscrowerStorage {
    struct Layout {
        mapping(address => mapping(bytes32 => uint256)) ethscriptionReceivedOnBlockNumber;
    }

    bytes32 internal constant STORAGE_SLOT =
        keccak256(
            "ethscriptions.contracts.storage.EthscriptionsEscrowerStorage"
        );

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

contract EthscriptionsEscrower {
    error EthscriptionNotDeposited();
    error EthscriptionAlreadyReceivedFromSender();
    error InvalidEthscriptionLength();
    error AdditionalCooldownRequired(uint256 additionalBlocksNeeded);

    event ethscriptions_protocol_TransferEthscriptionForPreviousOwner(
        address indexed previousOwner,
        address indexed recipient,
        bytes32 indexed id
    );

    event PotentialEthscriptionDeposited(
        address indexed owner,
        bytes32 indexed potentialEthscriptionId
    );

    event PotentialEthscriptionWithdrawn(
        address indexed owner,
        bytes32 indexed potentialEthscriptionId
    );

    uint256 public constant ETHSCRIPTION_TRANSFER_COOLDOWN_BLOCKS = 5;

    function _transferEthscription(
        address previousOwner,
        address to,
        bytes32 ethscriptionId
    ) internal virtual {
        _validateTransferEthscription(previousOwner, to, ethscriptionId);

        emit ethscriptions_protocol_TransferEthscriptionForPreviousOwner(
            previousOwner,
            to,
            ethscriptionId
        );

        _afterTransferEthscription(previousOwner, to, ethscriptionId);
    }

    function withdrawEthscription(bytes32 ethscriptionId) public virtual {
        _transferEthscription(msg.sender, msg.sender, ethscriptionId);

        emit PotentialEthscriptionWithdrawn(msg.sender, ethscriptionId);
    }

    function _onPotentialEthscriptionDeposit(
        address previousOwner,
        bytes memory userCalldata
    ) internal virtual {
        if (userCalldata.length != 32) revert InvalidEthscriptionLength();

        bytes32 potentialEthscriptionId = abi.decode(userCalldata, (bytes32));

        if (
            userEthscriptionPossiblyStored(
                previousOwner,
                potentialEthscriptionId
            )
        ) {
            revert EthscriptionAlreadyReceivedFromSender();
        }

        EthscriptionsEscrowerStorage.s().ethscriptionReceivedOnBlockNumber[
            previousOwner
        ][potentialEthscriptionId] = block.number;

        emit PotentialEthscriptionDeposited(
            previousOwner,
            potentialEthscriptionId
        );
    }

    function _validateTransferEthscription(
        address previousOwner,
        address to,
        bytes32 ethscriptionId
    ) internal view virtual {
        if (
            userEthscriptionDefinitelyNotStored(previousOwner, ethscriptionId)
        ) {
            revert EthscriptionNotDeposited();
        }

        uint256 blocksRemaining = blocksRemainingUntilValidTransfer(
            previousOwner,
            ethscriptionId
        );

        if (blocksRemaining != 0) {
            revert AdditionalCooldownRequired(blocksRemaining);
        }
    }

    function _afterTransferEthscription(
        address previousOwner,
        address to,
        bytes32 ethscriptionId
    ) internal virtual {
        delete EthscriptionsEscrowerStorage
            .s()
            .ethscriptionReceivedOnBlockNumber[previousOwner][ethscriptionId];
    }

    function blocksRemainingUntilValidTransfer(
        address previousOwner,
        bytes32 ethscriptionId
    ) public view virtual returns (uint256) {
        uint256 receivedBlockNumber = EthscriptionsEscrowerStorage
            .s()
            .ethscriptionReceivedOnBlockNumber[previousOwner][ethscriptionId];

        if (receivedBlockNumber == 0) {
            revert EthscriptionNotDeposited();
        }

        uint256 blocksPassed = block.number - receivedBlockNumber;

        return
            blocksPassed < ETHSCRIPTION_TRANSFER_COOLDOWN_BLOCKS
                ? ETHSCRIPTION_TRANSFER_COOLDOWN_BLOCKS - blocksPassed
                : 0;
    }

    function userEthscriptionDefinitelyNotStored(
        address owner,
        bytes32 ethscriptionId
    ) public view virtual returns (bool) {
        return
            EthscriptionsEscrowerStorage.s().ethscriptionReceivedOnBlockNumber[
                owner
            ][ethscriptionId] == 0;
    }

    function userEthscriptionPossiblyStored(
        address owner,
        bytes32 ethscriptionId
    ) public view virtual returns (bool) {
        return !userEthscriptionDefinitelyNotStored(owner, ethscriptionId);
    }
}

File 15 of 17 : ECDSA.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Gas optimized ECDSA wrapper.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
///
/// @dev Note:
/// - The recovery functions use the ecrecover precompile (0x1).
///
/// WARNING! Do NOT use signatures as unique identifiers.
/// Please use EIP712 with a nonce included in the digest to prevent replay attacks.
/// This implementation does NOT check if a signature is non-malleable.
library ECDSA {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        CUSTOM ERRORS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The signature is invalid.
    error InvalidSignature();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    RECOVERY OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // Note: as of Solady version 0.0.68, these functions will
    // revert upon recovery failure for more safety by default.

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function recover(bytes32 hash, bytes memory signature) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let signatureLength := mload(signature)
            mstore(0x00, hash)
            mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
            mstore(0x40, mload(add(signature, 0x20))) // `r`.
            mstore(0x60, mload(add(signature, 0x40))) // `s`.
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        eq(signatureLength, 65), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function recoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
            calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        eq(signature.length, 65), // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    ///
    /// This function only accepts EIP-2098 short form signatures.
    /// See: https://eips.ethereum.org/EIPS/eip-2098
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            result :=
                mload(
                    staticcall(
                        gas(), // Amount of gas left for the transaction.
                        1, // Address of `ecrecover`.
                        0x00, // Start of input.
                        0x80, // Size of input.
                        0x01, // Start of output.
                        0x20 // Size of output.
                    )
                )
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            if iszero(returndatasize()) {
                mstore(0x00, 0x8baa579f) // `InvalidSignature()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   TRY-RECOVER OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // WARNING!
    // These functions will NOT revert upon recovery failure.
    // Instead, they will return the zero address upon recovery failure.
    // It is critical that the returned address is NEVER compared against
    // a zero address (e.g. an uninitialized address variable).

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function tryRecover(bytes32 hash, bytes memory signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            let signatureLength := mload(signature)
            mstore(0x00, hash)
            mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
            mstore(0x40, mload(add(signature, 0x20))) // `r`.
            mstore(0x60, mload(add(signature, 0x40))) // `s`.
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    eq(signatureLength, 65), // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the `signature`.
    ///
    /// This function does NOT accept EIP-2098 short form signatures.
    /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098
    /// short form signatures instead.
    function tryRecoverCalldata(bytes32 hash, bytes calldata signature)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
            calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`.
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    eq(signature.length, 65), // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the EIP-2098 short form signature defined by `r` and `vs`.
    ///
    /// This function only accepts EIP-2098 short form signatures.
    /// See: https://eips.ethereum.org/EIPS/eip-2098
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, add(shr(255, vs), 27)) // `v`.
            mstore(0x40, r)
            mstore(0x60, shr(1, shl(1, vs))) // `s`.
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    1, // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Recovers the signer's address from a message digest `hash`,
    /// and the signature defined by `v`, `r`, `s`.
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s)
        internal
        view
        returns (address result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x00, hash)
            mstore(0x20, and(v, 0xff))
            mstore(0x40, r)
            mstore(0x60, s)
            pop(
                staticcall(
                    gas(), // Amount of gas left for the transaction.
                    1, // Address of `ecrecover`.
                    0x00, // Start of input.
                    0x80, // Size of input.
                    0x40, // Start of output.
                    0x20 // Size of output.
                )
            )
            mstore(0x60, 0) // Restore the zero slot.
            // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.
            result := mload(xor(0x60, returndatasize()))
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     HASHING OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an Ethereum Signed Message, created from a `hash`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x20, hash) // Store into scratch space for keccak256.
            mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
            result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
        }
    }

    /// @dev Returns an Ethereum Signed Message, created from `s`.
    /// This produces a hash corresponding to the one signed with the
    /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
    /// JSON-RPC method as part of EIP-191.
    /// Note: Supports lengths of `s` up to 999999 bytes.
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            let sLength := mload(s)
            let o := 0x20
            mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
            mstore(0x00, 0x00)
            // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
            for { let temp := sLength } 1 {} {
                o := sub(o, 1)
                mstore8(o, add(48, mod(temp, 10)))
                temp := div(temp, 10)
                if iszero(temp) { break }
            }
            let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
            // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
            returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
            mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
            result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
            mstore(s, sLength) // Restore the length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   EMPTY CALLDATA HELPERS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns an empty calldata bytes.
    function emptySignature() internal pure returns (bytes calldata signature) {
        /// @solidity memory-safe-assembly
        assembly {
            signature.length := 0
        }
    }
}

File 16 of 17 : ERC1967FactoryConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice The address and bytecode of the canonical ERC1967Factory deployment.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ERC1967FactoryLib.sol)
/// @author jtriley-eth (https://github.com/jtriley-eth/minimum-viable-proxy)
///
/// @dev The canonical ERC1967Factory is deployed permissionlessly via
/// 0age's ImmutableCreate2Factory located at 0x0000000000FFe8B47B3e2130213B802212439497.
///
/// `ADDRESS = immutableCreate2Factory.safeCreate2(SALT, INITCODE)`
///
/// If the canonical ERC1967Factory has not been deployed on your EVM chain of choice,
/// please feel free to deploy via 0age's ImmutableCreate2Factory.
///
/// If 0age's ImmutableCreate2Factory has not been deployed on your EVM chain of choice,
/// please refer to 0age's ImmutableCreate2Factory deployment instructions at:
/// https://github.com/ProjectOpenSea/seaport/blob/main/docs/Deployment.md
///
/// Contract verification:
/// - Source code:
///   https://github.com/Vectorized/solady/blob/5212e50fef1f2ff1b1b5e03a5d276a0d23c02713/src/utils/ERC1967Factory.sol
///   (The EXACT source code is required. Use the file at the commit instead of the latest copy.)
/// - Optimization Enabled: Yes with 1000000 runs
/// - Compiler Version: v0.8.19+commit.7dd6d404
/// - Other Settings: default evmVersion, MIT license
library ERC1967FactoryConstants {
    /// @dev The canonical ERC1967Factory address for EVM chains.
    address internal constant ADDRESS = 0x0000000000006396FF2a80c067f99B3d2Ab4Df24;

    /// @dev The canonical ERC1967Factory bytecode for EVM chains.
    /// Useful for forge tests:
    /// `vm.etch(ADDRESS, BYTECODE)`.
    bytes internal constant BYTECODE =
        hex"6080604052600436106100b15760003560e01c8063545e7c611161006957806399a88ec41161004e57806399a88ec41461019d578063a97b90d5146101b0578063db4c545e146101c357600080fd5b8063545e7c61146101775780639623609d1461018a57600080fd5b80633729f9221161009a5780633729f922146101315780634314f120146101445780635414dff01461015757600080fd5b80631acfd02a146100b65780632abbef15146100d8575b600080fd5b3480156100c257600080fd5b506100d66100d1366004610604565b6101e6565b005b3480156100e457600080fd5b506101076100f3366004610637565b30600c908152600091909152602090205490565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61010761013f366004610652565b610237565b6101076101523660046106d7565b61024e565b34801561016357600080fd5b50610107610172366004610738565b610267565b610107610185366004610604565b61029a565b6100d66101983660046106d7565b6102af565b6100d66101ab366004610604565b61035f565b6101076101be366004610751565b610370565b3480156101cf57600080fd5b506101d86103a9565b604051908152602001610128565b30600c52816000526020600c2033815414610209576382b429006000526004601cfd5b81905580827f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f600080a35050565b60006102468484843685610370565b949350505050565b600061025e8585838087876103c2565b95945050505050565b6000806102726103a9565b905060ff600053806035523060601b6001528260155260556000209150600060355250919050565b60006102a88383368461024e565b9392505050565b30600c5283600052336020600c2054146102d1576382b429006000526004601cfd5b6040518381527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc602082015281836040830137600080836040018334895af1610331573d610327576355299b496000526004601cfd5b3d6000803e3d6000fd5b5082847f5d611f318680d00598bb735d61bacf0c514c6b50e1e5ad30040a4df2b12791c7600080a350505050565b61036c82823660006102af565b5050565b60008360601c33148460601c151761039057632f6348366000526004601cfd5b61039f868686600187876103c2565b9695505050505050565b6000806103b461049c565b608960139091012092915050565b6000806103cd61049c565b90508480156103e757866089601384016000f592506103f3565b6089601383016000f092505b50816104075763301164256000526004601cfd5b8781527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc602082015282846040830137600080846040018334865af161045a573d6103275763301164256000526004601cfd5b30600c5281600052866020600c20558688837fc95935a66d15e0da5e412aca0ad27ae891d20b2fb91cf3994b6a3bf2b8178082600080a4509695505050505050565b6040513060701c801561054257666052573d6000fd607b8301527f3d356020355560408036111560525736038060403d373d3d355af43d6000803e60748301527f3735a920a3ca505d382bbc545af43d6000803e6052573d6000fd5b3d6000f35b60548301527f14605757363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc60348301523060148301526c607f3d8160093d39f33d3d337382525090565b66604c573d6000fd60758301527f3d3560203555604080361115604c5736038060403d373d3d355af43d6000803e606e8301527f3735a920a3ca505d382bbc545af43d6000803e604c573d6000fd5b3d6000f35b604e8301527f14605157363d3d37363d7f360894a13ba1a3210667c828492db98dca3e2076cc602e83015230600e8301526c60793d8160093d39f33d3d336d82525090565b803573ffffffffffffffffffffffffffffffffffffffff811681146105ff57600080fd5b919050565b6000806040838503121561061757600080fd5b610620836105db565b915061062e602084016105db565b90509250929050565b60006020828403121561064957600080fd5b6102a8826105db565b60008060006060848603121561066757600080fd5b610670846105db565b925061067e602085016105db565b9150604084013590509250925092565b60008083601f8401126106a057600080fd5b50813567ffffffffffffffff8111156106b857600080fd5b6020830191508360208285010111156106d057600080fd5b9250929050565b600080600080606085870312156106ed57600080fd5b6106f6856105db565b9350610704602086016105db565b9250604085013567ffffffffffffffff81111561072057600080fd5b61072c8782880161068e565b95989497509550505050565b60006020828403121561074a57600080fd5b5035919050565b60008060008060006080868803121561076957600080fd5b610772866105db565b9450610780602087016105db565b935060408601359250606086013567ffffffffffffffff8111156107a357600080fd5b6107af8882890161068e565b96999598509396509294939250505056fea26469706673582212200ac7c3ccbc2d311c48bf5465b021542e0e306fe3c462c060ba6a3d2f81ff6c5f64736f6c63430008130033";

    /// @dev The initcode used to deploy the canonical ERC1967Factory.
    bytes internal constant INITCODE = abi.encodePacked(
        hex"608060405234801561001057600080fd5b506107f6806100206000396000f3fe", BYTECODE
    );

    /// @dev For deterministic deployment via 0age's ImmutableCreate2Factory.
    bytes32 internal constant SALT =
        0x0000000000000000000000000000000000000000e75e4f228818c80007508f33;
}

File 17 of 17 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
/// - For ERC20s, this implementation won't check that a token has code,
///   responsibility is delegated to the caller.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for
    /// the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                    call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                )
            ) {
                mstore(0x34, 0) // Store 0 for the `amount`.
                mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) // Reset the approval.
                mstore(0x34, amount) // Store back the original `amount`.
                // Retry the approval, reverting upon failure.
                if iszero(
                    and(
                        or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.
                        call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    )
                ) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul(
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }
}

Settings
{
  "evmVersion": "paris",
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"additionalBlocksNeeded","type":"uint256"}],"name":"AdditionalCooldownRequired","type":"error"},{"inputs":[],"name":"EthscriptionAlreadyReceivedFromSender","type":"error"},{"inputs":[],"name":"EthscriptionNotDeposited","type":"error"},{"inputs":[],"name":"InvalidEthscriptionLength","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuard__ReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"EthscriptionDelisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":true,"internalType":"address","name":"seller","type":"address"}],"name":"EthscriptionListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":true,"internalType":"address","name":"seller","type":"address"},{"indexed":true,"internalType":"address","name":"buyer","type":"address"}],"name":"EthscriptionPurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"bytes32","name":"potentialEthscriptionId","type":"bytes32"}],"name":"PotentialEthscriptionDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"bytes32","name":"potentialEthscriptionId","type":"bytes32"}],"name":"PotentialEthscriptionWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ethscriptions_protocol_TransferEthscriptionForPreviousOwner","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"ETHSCRIPTION_TRANSFER_COOLDOWN_BLOCKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"ethscriptionIds","type":"bytes32[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"}],"name":"batchBuyEthscription","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"ethscriptionIds","type":"bytes32[]"},{"internalType":"uint256[]","name":"prices","type":"uint256[]"}],"name":"batchListEthscriptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"previousOwner","type":"address"},{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"}],"name":"blocksRemainingUntilValidTransfer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"buyEthscription","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"}],"name":"delistEthscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ethscriptionsOfferedForSale","outputs":[{"internalType":"bool","name":"isForSale","type":"bool"},{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feesAccumulated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"},{"internalType":"uint256","name":"price","type":"uint256"}],"name":"listEthscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"updatedFee","type":"uint256"}],"name":"setMarketPlaceFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferContractOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"}],"name":"userEthscriptionDefinitelyNotStored","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"}],"name":"userEthscriptionPossiblyStored","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"ethscriptionId","type":"bytes32"}],"name":"withdrawEthscription","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260fa60015560006002553480156200001b57600080fd5b5033600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603620000925760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401620000899190620001b3565b60405180910390fd5b620000a381620000aa60201b60201c565b50620001d0565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200019b826200016e565b9050919050565b620001ad816200018e565b82525050565b6000602082019050620001ca6000830184620001a2565b92915050565b61257f80620001e06000396000f3fe6080604052600436106101235760003560e01c80638da5cb5b116100a0578063d73792a911610064578063d73792a9146103f0578063ddca3f431461041b578063e7b59bf314610446578063e9bf95a21461046f578063f2fde38b146104ac57610124565b80638da5cb5b1461030b578063aa3bf60e14610336578063c20925c914610373578063c465e49f1461039c578063ccad70f1146103c757610124565b80635db74d20116100e75780635db74d2014610246578063642b31da14610286578063715018a6146102a25780637229e670146102b9578063892d15da146102e257610124565b806318349111146101825780633ddf97f1146101ad578063476343ee146101c95780634f868776146101e05780635cad65a11461020957610124565b5b34801561013057600080fd5b50610180336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506104d5565b005b34801561018e57600080fd5b50610197610624565b6040516101a491906119b1565b60405180910390f35b6101c760048036038101906101c29190611a9b565b61062a565b005b3480156101d557600080fd5b506101de610790565b005b3480156101ec57600080fd5b5061020760048036038101906102029190611b7e565b6107f1565b005b34801561021557600080fd5b50610230600480360381019061022b9190611c1c565b61084e565b60405161023d9190611c77565b60405180910390f35b34801561025257600080fd5b5061026d60048036038101906102689190611c92565b610863565b60405161027d9493929190611cdd565b60405180910390f35b6102a0600480360381019061029b9190611b7e565b6108c0565b005b3480156102ae57600080fd5b506102b761091d565b005b3480156102c557600080fd5b506102e060048036038101906102db9190611f34565b610931565b005b3480156102ee57600080fd5b5061030960048036038101906103049190611c92565b610a26565b005b34801561031757600080fd5b50610320610bd2565b60405161032d9190611fac565b60405180910390f35b34801561034257600080fd5b5061035d60048036038101906103589190611c1c565b610bfb565b60405161036a9190611c77565b60405180910390f35b34801561037f57600080fd5b5061039a60048036038101906103959190611fc7565b610c61565b005b3480156103a857600080fd5b506103b1610c73565b6040516103be91906119b1565b60405180910390f35b3480156103d357600080fd5b506103ee60048036038101906103e99190611c92565b610c78565b005b3480156103fc57600080fd5b50610405610d8a565b60405161041291906119b1565b60405180910390f35b34801561042757600080fd5b50610430610d90565b60405161043d91906119b1565b60405180910390f35b34801561045257600080fd5b5061046d60048036038101906104689190611ff4565b610d96565b005b34801561047b57600080fd5b5061049660048036038101906104919190611c1c565b610daa565b6040516104a391906119b1565b60405180910390f35b3480156104b857600080fd5b506104d360048036038101906104ce9190611ff4565b610e7a565b005b6000602082516104e59190612050565b14610525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161051c906120de565b60405180910390fd5b60005b60208251610536919061212d565b81101561061f57600061055783602084610550919061215e565b6020610f00565b80602001905181019061056a91906121b5565b9050610576848261084e565b156105ad576040517f92aa23a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b436105b6610fe8565b60000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550508080610617906121e2565b915050610528565b505050565b60025481565b610632611015565b15610669576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61067161102b565b8181905084849050146106b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b090612276565b60405180910390fd5b6000805b8585905081101561073e576107048686838181106106de576106dd612296565b5b905060200201358585848181106106f8576106f7612296565b5b9050602002013561103e565b83838281811061071757610716612296565b5b905060200201358261072991906122c5565b91508080610736906121e2565b9150506106bd565b50803414610781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077890612345565b60405180910390fd5b5061078a6113c6565b50505050565b6107986113d9565b6000600254905060006002819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156107ed573d6000803e3d6000fd5b5050565b6107f9611015565b15610830576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61083861102b565b6108428282611460565b61084a6113c6565b5050565b600061085a8383610bfb565b15905092915050565b60036020528060005260406000206000915090508060000160009054906101000a900460ff16908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6108c8611015565b156108ff576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61090761102b565b610911828261103e565b6109196113c6565b5050565b6109256113d9565b61092f60006115c8565b565b610939611015565b15610970576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097861102b565b80518251146109bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109b390612276565b60405180910390fd5b60005b8251811015610a1957610a068382815181106109de576109dd612296565b5b60200260200101518383815181106109f9576109f8612296565b5b6020026020010151611460565b8080610a11906121e2565b9150506109bf565b50610a226113c6565b5050565b610a2e611015565b15610a65576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a6d61102b565b610a773382610bfb565b15610ab7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aae906123b1565b60405180910390fd5b60405180608001604052806000151581526020018281526020013373ffffffffffffffffffffffffffffffffffffffff16815260200160008152506003600083815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff16817ffbe304b5920fbd69012a7c05a0ebc9a10c224363ac30d77cc2f0fd7c87c329ef60405160405180910390a3610bcf6113c6565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080610c06610fe8565b60000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000205414905092915050565b610c696113d9565b8060018190555050565b600581565b610c823382610bfb565b15610cc2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb9906123b1565b60405180910390fd5b610ccb8161168c565b6000600360008381526020019081526020016000206040518060800160405290816000820160009054906101000a900460ff16151515158152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820154815250509050806000015115610d8657610d85826116de565b5b5050565b61271081565b60015481565b610d9e6113d9565b610da781610e7a565b50565b600080610db5610fe8565b60000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905060008103610e43576040517f62ef5a1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008143610e5191906123d1565b905060058110610e62576000610e70565b806005610e6f91906123d1565b5b9250505092915050565b610e826113d9565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610ef45760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610eeb9190611fac565b60405180910390fd5b610efd816115c8565b50565b606060008267ffffffffffffffff811115610f1e57610f1d611d33565b5b6040519080825280601f01601f191660200182016040528015610f505781602001600182028036833780820191505090505b50905060005b83811015610fdc57858582610f6b91906122c5565b81518110610f7c57610f7b612296565b5b602001015160f81c60f81b828281518110610f9a57610f99612296565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610fd4906121e2565b915050610f56565b50809150509392505050565b6000807fa282d38759ca2a57f8989aea0c5822bcfbf65ad49415379bdbc35dbb78efd8da90508091505090565b600060026110216117f1565b6000015414905090565b60026110356117f1565b60000181905550565b6000600360008481526020019081526020016000206040518060800160405290816000820160009054906101000a900460ff16151515158152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160038201548152505090508060000151611129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112090612451565b60405180910390fd5b8060600151341461116f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611166906124bd565b60405180910390fd5b6000816040015190503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111dd90612529565b60405180910390fd5b60405180608001604052806000151581526020018581526020013373ffffffffffffffffffffffffffffffffffffffff16815260200160008152506003600086815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050506112bd81338661181e565b600061271060015484606001516112d4919061215e565b6112de919061212d565b905060008184606001516112f291906123d1565b9050816002600082825461130691906122c5565b925050819055508273ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611353573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16877ff85d0c07d27fabeb455264c591cac3a67f6958aaa9f46fba618eed45c283b49987606001516040516113b691906119b1565b60405180910390a4505050505050565b60016113d06117f1565b60000181905550565b6113e1611894565b73ffffffffffffffffffffffffffffffffffffffff166113ff610bd2565b73ffffffffffffffffffffffffffffffffffffffff161461145e57611422611894565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016114559190611fac565b60405180910390fd5b565b61146a3383610bfb565b156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114a1906123b1565b60405180910390fd5b60405180608001604052806001151581526020018381526020013373ffffffffffffffffffffffffffffffffffffffff168152602001828152506003600084815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff16827fe3f89e533982f732fc486dee2bc0e466acc85c387ae7f40a9e3233a2948c9aa7836040516115bc91906119b1565b60405180910390a35050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b61169733338361181e565b803373ffffffffffffffffffffffffffffffffffffffff167f745e9ff25e7b8746bcb27c63375e46ce8ad40fd3a91c1349613f7edba7c411fe60405160405180910390a350565b60405180608001604052806000151581526020018281526020013373ffffffffffffffffffffffffffffffffffffffff16815260200160008152506003600083815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff16817ffbe304b5920fbd69012a7c05a0ebc9a10c224363ac30d77cc2f0fd7c87c329ef60405160405180910390a350565b6000807f09acf4e54214992e70883cf7dcd6957ff2c71cd9e14df4bec4383bc0d11607dc90508091505090565b61182983838361189c565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167ff1d95ed4d1680e6f665104f19c296ae52c1f64cd8114e84d55dc6349dbdafea360405160405180910390a461188f838383611936565b505050565b600033905090565b6118a68382610bfb565b156118dd576040517f62ef5a1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118e98483610daa565b90506000811461193057806040517fc91eebe400000000000000000000000000000000000000000000000000000000815260040161192791906119b1565b60405180910390fd5b50505050565b61193e610fe8565b60000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082815260200190815260200160002060009055505050565b6000819050919050565b6119ab81611998565b82525050565b60006020820190506119c660008301846119a2565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112611a0557611a046119e0565b5b8235905067ffffffffffffffff811115611a2257611a216119e5565b5b602083019150836020820283011115611a3e57611a3d6119ea565b5b9250929050565b60008083601f840112611a5b57611a5a6119e0565b5b8235905067ffffffffffffffff811115611a7857611a776119e5565b5b602083019150836020820283011115611a9457611a936119ea565b5b9250929050565b60008060008060408587031215611ab557611ab46119d6565b5b600085013567ffffffffffffffff811115611ad357611ad26119db565b5b611adf878288016119ef565b9450945050602085013567ffffffffffffffff811115611b0257611b016119db565b5b611b0e87828801611a45565b925092505092959194509250565b6000819050919050565b611b2f81611b1c565b8114611b3a57600080fd5b50565b600081359050611b4c81611b26565b92915050565b611b5b81611998565b8114611b6657600080fd5b50565b600081359050611b7881611b52565b92915050565b60008060408385031215611b9557611b946119d6565b5b6000611ba385828601611b3d565b9250506020611bb485828601611b69565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611be982611bbe565b9050919050565b611bf981611bde565b8114611c0457600080fd5b50565b600081359050611c1681611bf0565b92915050565b60008060408385031215611c3357611c326119d6565b5b6000611c4185828601611c07565b9250506020611c5285828601611b3d565b9150509250929050565b60008115159050919050565b611c7181611c5c565b82525050565b6000602082019050611c8c6000830184611c68565b92915050565b600060208284031215611ca857611ca76119d6565b5b6000611cb684828501611b3d565b91505092915050565b611cc881611b1c565b82525050565b611cd781611bde565b82525050565b6000608082019050611cf26000830187611c68565b611cff6020830186611cbf565b611d0c6040830185611cce565b611d1960608301846119a2565b95945050505050565b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611d6b82611d22565b810181811067ffffffffffffffff82111715611d8a57611d89611d33565b5b80604052505050565b6000611d9d6119cc565b9050611da98282611d62565b919050565b600067ffffffffffffffff821115611dc957611dc8611d33565b5b602082029050602081019050919050565b6000611ded611de884611dae565b611d93565b90508083825260208201905060208402830185811115611e1057611e0f6119ea565b5b835b81811015611e395780611e258882611b3d565b845260208401935050602081019050611e12565b5050509392505050565b600082601f830112611e5857611e576119e0565b5b8135611e68848260208601611dda565b91505092915050565b600067ffffffffffffffff821115611e8c57611e8b611d33565b5b602082029050602081019050919050565b6000611eb0611eab84611e71565b611d93565b90508083825260208201905060208402830185811115611ed357611ed26119ea565b5b835b81811015611efc5780611ee88882611b69565b845260208401935050602081019050611ed5565b5050509392505050565b600082601f830112611f1b57611f1a6119e0565b5b8135611f2b848260208601611e9d565b91505092915050565b60008060408385031215611f4b57611f4a6119d6565b5b600083013567ffffffffffffffff811115611f6957611f686119db565b5b611f7585828601611e43565b925050602083013567ffffffffffffffff811115611f9657611f956119db565b5b611fa285828601611f06565b9150509250929050565b6000602082019050611fc16000830184611cce565b92915050565b600060208284031215611fdd57611fdc6119d6565b5b6000611feb84828501611b69565b91505092915050565b60006020828403121561200a576120096119d6565b5b600061201884828501611c07565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061205b82611998565b915061206683611998565b92508261207657612075612021565b5b828206905092915050565b600082825260208201905092915050565b7f496e76616c6964457468736372697074696f6e4c656e67746800000000000000600082015250565b60006120c8601983612081565b91506120d382612092565b602082019050919050565b600060208201905081810360008301526120f7816120bb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061213882611998565b915061214383611998565b92508261215357612152612021565b5b828204905092915050565b600061216982611998565b915061217483611998565b925082820261218281611998565b91508282048414831517612199576121986120fe565b5b5092915050565b6000815190506121af81611b26565b92915050565b6000602082840312156121cb576121ca6119d6565b5b60006121d9848285016121a0565b91505092915050565b60006121ed82611998565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361221f5761221e6120fe565b5b600182019050919050565b7f4172726179206c656e6774687320646f206e6f74206d61746368000000000000600082015250565b6000612260601a83612081565b915061226b8261222a565b602082019050919050565b6000602082019050818103600083015261228f81612253565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006122d082611998565b91506122db83611998565b92508282019050808211156122f3576122f26120fe565b5b92915050565b7f496e636f727265637420746f74616c2045746865722073656e74000000000000600082015250565b600061232f601a83612081565b915061233a826122f9565b602082019050919050565b6000602082019050818103600083015261235e81612322565b9050919050565b7f53656e646572206973206e6f74206465706f7369746f72000000000000000000600082015250565b600061239b601783612081565b91506123a682612365565b602082019050919050565b600060208201905081810360008301526123ca8161238e565b9050919050565b60006123dc82611998565b91506123e783611998565b92508282039050818111156123ff576123fe6120fe565b5b92915050565b7f457468736372697074696f6e206973206e6f7420666f722073616c6500000000600082015250565b600061243b601c83612081565b915061244682612405565b602082019050919050565b6000602082019050818103600083015261246a8161242e565b9050919050565b7f4e6f7420656e6f75676820657468657200000000000000000000000000000000600082015250565b60006124a7601083612081565b91506124b282612471565b602082019050919050565b600060208201905081810360008301526124d68161249a565b9050919050565b7f53656c6c65722069732062757965720000000000000000000000000000000000600082015250565b6000612513600f83612081565b915061251e826124dd565b602082019050919050565b6000602082019050818103600083015261254281612506565b905091905056fea2646970667358221220a7403deeaae6becd3b997b8e51fbc26a9444721b1ddc81d76441f389126791ce64736f6c63430008140033

Deployed Bytecode

0x6080604052600436106101235760003560e01c80638da5cb5b116100a0578063d73792a911610064578063d73792a9146103f0578063ddca3f431461041b578063e7b59bf314610446578063e9bf95a21461046f578063f2fde38b146104ac57610124565b80638da5cb5b1461030b578063aa3bf60e14610336578063c20925c914610373578063c465e49f1461039c578063ccad70f1146103c757610124565b80635db74d20116100e75780635db74d2014610246578063642b31da14610286578063715018a6146102a25780637229e670146102b9578063892d15da146102e257610124565b806318349111146101825780633ddf97f1146101ad578063476343ee146101c95780634f868776146101e05780635cad65a11461020957610124565b5b34801561013057600080fd5b50610180336000368080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050506104d5565b005b34801561018e57600080fd5b50610197610624565b6040516101a491906119b1565b60405180910390f35b6101c760048036038101906101c29190611a9b565b61062a565b005b3480156101d557600080fd5b506101de610790565b005b3480156101ec57600080fd5b5061020760048036038101906102029190611b7e565b6107f1565b005b34801561021557600080fd5b50610230600480360381019061022b9190611c1c565b61084e565b60405161023d9190611c77565b60405180910390f35b34801561025257600080fd5b5061026d60048036038101906102689190611c92565b610863565b60405161027d9493929190611cdd565b60405180910390f35b6102a0600480360381019061029b9190611b7e565b6108c0565b005b3480156102ae57600080fd5b506102b761091d565b005b3480156102c557600080fd5b506102e060048036038101906102db9190611f34565b610931565b005b3480156102ee57600080fd5b5061030960048036038101906103049190611c92565b610a26565b005b34801561031757600080fd5b50610320610bd2565b60405161032d9190611fac565b60405180910390f35b34801561034257600080fd5b5061035d60048036038101906103589190611c1c565b610bfb565b60405161036a9190611c77565b60405180910390f35b34801561037f57600080fd5b5061039a60048036038101906103959190611fc7565b610c61565b005b3480156103a857600080fd5b506103b1610c73565b6040516103be91906119b1565b60405180910390f35b3480156103d357600080fd5b506103ee60048036038101906103e99190611c92565b610c78565b005b3480156103fc57600080fd5b50610405610d8a565b60405161041291906119b1565b60405180910390f35b34801561042757600080fd5b50610430610d90565b60405161043d91906119b1565b60405180910390f35b34801561045257600080fd5b5061046d60048036038101906104689190611ff4565b610d96565b005b34801561047b57600080fd5b5061049660048036038101906104919190611c1c565b610daa565b6040516104a391906119b1565b60405180910390f35b3480156104b857600080fd5b506104d360048036038101906104ce9190611ff4565b610e7a565b005b6000602082516104e59190612050565b14610525576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161051c906120de565b60405180910390fd5b60005b60208251610536919061212d565b81101561061f57600061055783602084610550919061215e565b6020610f00565b80602001905181019061056a91906121b5565b9050610576848261084e565b156105ad576040517f92aa23a100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b436105b6610fe8565b60000160008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600083815260200190815260200160002081905550508080610617906121e2565b915050610528565b505050565b60025481565b610632611015565b15610669576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61067161102b565b8181905084849050146106b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106b090612276565b60405180910390fd5b6000805b8585905081101561073e576107048686838181106106de576106dd612296565b5b905060200201358585848181106106f8576106f7612296565b5b9050602002013561103e565b83838281811061071757610716612296565b5b905060200201358261072991906122c5565b91508080610736906121e2565b9150506106bd565b50803414610781576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161077890612345565b60405180910390fd5b5061078a6113c6565b50505050565b6107986113d9565b6000600254905060006002819055503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156107ed573d6000803e3d6000fd5b5050565b6107f9611015565b15610830576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61083861102b565b6108428282611460565b61084a6113c6565b5050565b600061085a8383610bfb565b15905092915050565b60036020528060005260406000206000915090508060000160009054906101000a900460ff16908060010154908060020160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060030154905084565b6108c8611015565b156108ff576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61090761102b565b610911828261103e565b6109196113c6565b5050565b6109256113d9565b61092f60006115c8565b565b610939611015565b15610970576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61097861102b565b80518251146109bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109b390612276565b60405180910390fd5b60005b8251811015610a1957610a068382815181106109de576109dd612296565b5b60200260200101518383815181106109f9576109f8612296565b5b6020026020010151611460565b8080610a11906121e2565b9150506109bf565b50610a226113c6565b5050565b610a2e611015565b15610a65576040517fbb6b8f9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a6d61102b565b610a773382610bfb565b15610ab7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aae906123b1565b60405180910390fd5b60405180608001604052806000151581526020018281526020013373ffffffffffffffffffffffffffffffffffffffff16815260200160008152506003600083815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff16817ffbe304b5920fbd69012a7c05a0ebc9a10c224363ac30d77cc2f0fd7c87c329ef60405160405180910390a3610bcf6113c6565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080610c06610fe8565b60000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008481526020019081526020016000205414905092915050565b610c696113d9565b8060018190555050565b600581565b610c823382610bfb565b15610cc2576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cb9906123b1565b60405180910390fd5b610ccb8161168c565b6000600360008381526020019081526020016000206040518060800160405290816000820160009054906101000a900460ff16151515158152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020016003820154815250509050806000015115610d8657610d85826116de565b5b5050565b61271081565b60015481565b610d9e6113d9565b610da781610e7a565b50565b600080610db5610fe8565b60000160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600084815260200190815260200160002054905060008103610e43576040517f62ef5a1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008143610e5191906123d1565b905060058110610e62576000610e70565b806005610e6f91906123d1565b5b9250505092915050565b610e826113d9565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610ef45760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610eeb9190611fac565b60405180910390fd5b610efd816115c8565b50565b606060008267ffffffffffffffff811115610f1e57610f1d611d33565b5b6040519080825280601f01601f191660200182016040528015610f505781602001600182028036833780820191505090505b50905060005b83811015610fdc57858582610f6b91906122c5565b81518110610f7c57610f7b612296565b5b602001015160f81c60f81b828281518110610f9a57610f99612296565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508080610fd4906121e2565b915050610f56565b50809150509392505050565b6000807fa282d38759ca2a57f8989aea0c5822bcfbf65ad49415379bdbc35dbb78efd8da90508091505090565b600060026110216117f1565b6000015414905090565b60026110356117f1565b60000181905550565b6000600360008481526020019081526020016000206040518060800160405290816000820160009054906101000a900460ff16151515158152602001600182015481526020016002820160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160038201548152505090508060000151611129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112090612451565b60405180910390fd5b8060600151341461116f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611166906124bd565b60405180910390fd5b6000816040015190503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036111e6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016111dd90612529565b60405180910390fd5b60405180608001604052806000151581526020018581526020013373ffffffffffffffffffffffffffffffffffffffff16815260200160008152506003600086815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050506112bd81338661181e565b600061271060015484606001516112d4919061215e565b6112de919061212d565b905060008184606001516112f291906123d1565b9050816002600082825461130691906122c5565b925050819055508273ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611353573d6000803e3d6000fd5b503373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16877ff85d0c07d27fabeb455264c591cac3a67f6958aaa9f46fba618eed45c283b49987606001516040516113b691906119b1565b60405180910390a4505050505050565b60016113d06117f1565b60000181905550565b6113e1611894565b73ffffffffffffffffffffffffffffffffffffffff166113ff610bd2565b73ffffffffffffffffffffffffffffffffffffffff161461145e57611422611894565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016114559190611fac565b60405180910390fd5b565b61146a3383610bfb565b156114aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016114a1906123b1565b60405180910390fd5b60405180608001604052806001151581526020018381526020013373ffffffffffffffffffffffffffffffffffffffff168152602001828152506003600084815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff16827fe3f89e533982f732fc486dee2bc0e466acc85c387ae7f40a9e3233a2948c9aa7836040516115bc91906119b1565b60405180910390a35050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b61169733338361181e565b803373ffffffffffffffffffffffffffffffffffffffff167f745e9ff25e7b8746bcb27c63375e46ce8ad40fd3a91c1349613f7edba7c411fe60405160405180910390a350565b60405180608001604052806000151581526020018281526020013373ffffffffffffffffffffffffffffffffffffffff16815260200160008152506003600083815260200190815260200160002060008201518160000160006101000a81548160ff0219169083151502179055506020820151816001015560408201518160020160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550606082015181600301559050503373ffffffffffffffffffffffffffffffffffffffff16817ffbe304b5920fbd69012a7c05a0ebc9a10c224363ac30d77cc2f0fd7c87c329ef60405160405180910390a350565b6000807f09acf4e54214992e70883cf7dcd6957ff2c71cd9e14df4bec4383bc0d11607dc90508091505090565b61182983838361189c565b808273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167ff1d95ed4d1680e6f665104f19c296ae52c1f64cd8114e84d55dc6349dbdafea360405160405180910390a461188f838383611936565b505050565b600033905090565b6118a68382610bfb565b156118dd576040517f62ef5a1900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006118e98483610daa565b90506000811461193057806040517fc91eebe400000000000000000000000000000000000000000000000000000000815260040161192791906119b1565b60405180910390fd5b50505050565b61193e610fe8565b60000160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082815260200190815260200160002060009055505050565b6000819050919050565b6119ab81611998565b82525050565b60006020820190506119c660008301846119a2565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112611a0557611a046119e0565b5b8235905067ffffffffffffffff811115611a2257611a216119e5565b5b602083019150836020820283011115611a3e57611a3d6119ea565b5b9250929050565b60008083601f840112611a5b57611a5a6119e0565b5b8235905067ffffffffffffffff811115611a7857611a776119e5565b5b602083019150836020820283011115611a9457611a936119ea565b5b9250929050565b60008060008060408587031215611ab557611ab46119d6565b5b600085013567ffffffffffffffff811115611ad357611ad26119db565b5b611adf878288016119ef565b9450945050602085013567ffffffffffffffff811115611b0257611b016119db565b5b611b0e87828801611a45565b925092505092959194509250565b6000819050919050565b611b2f81611b1c565b8114611b3a57600080fd5b50565b600081359050611b4c81611b26565b92915050565b611b5b81611998565b8114611b6657600080fd5b50565b600081359050611b7881611b52565b92915050565b60008060408385031215611b9557611b946119d6565b5b6000611ba385828601611b3d565b9250506020611bb485828601611b69565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000611be982611bbe565b9050919050565b611bf981611bde565b8114611c0457600080fd5b50565b600081359050611c1681611bf0565b92915050565b60008060408385031215611c3357611c326119d6565b5b6000611c4185828601611c07565b9250506020611c5285828601611b3d565b9150509250929050565b60008115159050919050565b611c7181611c5c565b82525050565b6000602082019050611c8c6000830184611c68565b92915050565b600060208284031215611ca857611ca76119d6565b5b6000611cb684828501611b3d565b91505092915050565b611cc881611b1c565b82525050565b611cd781611bde565b82525050565b6000608082019050611cf26000830187611c68565b611cff6020830186611cbf565b611d0c6040830185611cce565b611d1960608301846119a2565b95945050505050565b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b611d6b82611d22565b810181811067ffffffffffffffff82111715611d8a57611d89611d33565b5b80604052505050565b6000611d9d6119cc565b9050611da98282611d62565b919050565b600067ffffffffffffffff821115611dc957611dc8611d33565b5b602082029050602081019050919050565b6000611ded611de884611dae565b611d93565b90508083825260208201905060208402830185811115611e1057611e0f6119ea565b5b835b81811015611e395780611e258882611b3d565b845260208401935050602081019050611e12565b5050509392505050565b600082601f830112611e5857611e576119e0565b5b8135611e68848260208601611dda565b91505092915050565b600067ffffffffffffffff821115611e8c57611e8b611d33565b5b602082029050602081019050919050565b6000611eb0611eab84611e71565b611d93565b90508083825260208201905060208402830185811115611ed357611ed26119ea565b5b835b81811015611efc5780611ee88882611b69565b845260208401935050602081019050611ed5565b5050509392505050565b600082601f830112611f1b57611f1a6119e0565b5b8135611f2b848260208601611e9d565b91505092915050565b60008060408385031215611f4b57611f4a6119d6565b5b600083013567ffffffffffffffff811115611f6957611f686119db565b5b611f7585828601611e43565b925050602083013567ffffffffffffffff811115611f9657611f956119db565b5b611fa285828601611f06565b9150509250929050565b6000602082019050611fc16000830184611cce565b92915050565b600060208284031215611fdd57611fdc6119d6565b5b6000611feb84828501611b69565b91505092915050565b60006020828403121561200a576120096119d6565b5b600061201884828501611c07565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600061205b82611998565b915061206683611998565b92508261207657612075612021565b5b828206905092915050565b600082825260208201905092915050565b7f496e76616c6964457468736372697074696f6e4c656e67746800000000000000600082015250565b60006120c8601983612081565b91506120d382612092565b602082019050919050565b600060208201905081810360008301526120f7816120bb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061213882611998565b915061214383611998565b92508261215357612152612021565b5b828204905092915050565b600061216982611998565b915061217483611998565b925082820261218281611998565b91508282048414831517612199576121986120fe565b5b5092915050565b6000815190506121af81611b26565b92915050565b6000602082840312156121cb576121ca6119d6565b5b60006121d9848285016121a0565b91505092915050565b60006121ed82611998565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361221f5761221e6120fe565b5b600182019050919050565b7f4172726179206c656e6774687320646f206e6f74206d61746368000000000000600082015250565b6000612260601a83612081565b915061226b8261222a565b602082019050919050565b6000602082019050818103600083015261228f81612253565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006122d082611998565b91506122db83611998565b92508282019050808211156122f3576122f26120fe565b5b92915050565b7f496e636f727265637420746f74616c2045746865722073656e74000000000000600082015250565b600061232f601a83612081565b915061233a826122f9565b602082019050919050565b6000602082019050818103600083015261235e81612322565b9050919050565b7f53656e646572206973206e6f74206465706f7369746f72000000000000000000600082015250565b600061239b601783612081565b91506123a682612365565b602082019050919050565b600060208201905081810360008301526123ca8161238e565b9050919050565b60006123dc82611998565b91506123e783611998565b92508282039050818111156123ff576123fe6120fe565b5b92915050565b7f457468736372697074696f6e206973206e6f7420666f722073616c6500000000600082015250565b600061243b601c83612081565b915061244682612405565b602082019050919050565b6000602082019050818103600083015261246a8161242e565b9050919050565b7f4e6f7420656e6f75676820657468657200000000000000000000000000000000600082015250565b60006124a7601083612081565b91506124b282612471565b602082019050919050565b600060208201905081810360008301526124d68161249a565b9050919050565b7f53656c6c65722069732062757965720000000000000000000000000000000000600082015250565b6000612513600f83612081565b915061251e826124dd565b602082019050919050565b6000602082019050818103600083015261254281612506565b905091905056fea2646970667358221220a7403deeaae6becd3b997b8e51fbc26a9444721b1ddc81d76441f389126791ce64736f6c63430008140033

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
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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