ETH Price: $2,560.74 (-3.24%)

Transaction Decoder

Block:
20316828 at Jul-16-2024 04:57:47 AM +UTC
Transaction Fee:
0.000143359596271008 ETH $0.37
Gas Used:
30,816 Gas / 4.652115663 Gwei

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
14.255810511184243794 Eth14.25583540248563109 Eth0.000024891301387296
0x75E5536f...4a0240f2e
0.041413279913304155 Eth
Nonce: 496
0.210269920317033147 Eth
Nonce: 497
0.168856640403728992
0xd6c037bE...35d2971e7 108.043979 Eth107.874979 Eth0.169

Execution Trace

CryptoPhunksMarket.CALL( )
  • ETH 0.169 0x75e5536f29477db412f1f6e9d8756824a0240f2e.CALL( )
    // SPDX-License-Identifier: MIT License
    pragma solidity 0.8.10;
    import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    import "@openzeppelin/contracts/utils/Context.sol";
    /**
     * @dev Contract module which allows children to implement an emergency stop
     * mechanism that can be triggered by an authorized account.
     *
     * This module is used through inheritance. It will make available the
     * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
     * the functions of your contract. Note that they will not be pausable by
     * simply including this module, only once the modifiers are put in place.
     */
    abstract contract Pausable is Context {
        /**
         * @dev Emitted when the pause is triggered by `account`.
         */
        event Paused(address account);
        /**
         * @dev Emitted when the pause is lifted by `account`.
         */
        event Unpaused(address account);
        bool private _paused;
        /**
         * @dev Initializes the contract in unpaused state.
         */
        constructor() {
            _paused = false;
        }
        /**
         * @dev Returns true if the contract is paused, and false otherwise.
         */
        function paused() public view virtual returns (bool) {
            return _paused;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is not paused.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        modifier whenNotPaused() {
            require(!paused(), "Pausable: paused");
            _;
        }
        /**
         * @dev Modifier to make a function callable only when the contract is paused.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        modifier whenPaused() {
            require(paused(), "Pausable: not paused");
            _;
        }
        /**
         * @dev Triggers stopped state.
         *
         * Requirements:
         *
         * - The contract must not be paused.
         */
        function _pause() internal virtual whenNotPaused {
            _paused = true;
            emit Paused(_msgSender());
        }
        /**
         * @dev Returns to normal state.
         *
         * Requirements:
         *
         * - The contract must be paused.
         */
        function _unpause() internal virtual whenPaused {
            _paused = false;
            emit Unpaused(_msgSender());
        }
    }
    /**
     * @dev Contract module which provides access control
     *
     * the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * mapped to 
     * `onlyOwner`
     */
    abstract contract Ownable is Context {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _setOwner(_msgSender());
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _setOwner(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 {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            _setOwner(newOwner);
        }
        
        function _setOwner(address newOwner) private {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    contract CryptoPhunksMarket is ReentrancyGuard, Pausable, Ownable {
        IERC721 phunksContract;     // instance of the CryptoPhunks contract
        struct Offer {
            bool isForSale;
            uint phunkIndex;
            address seller;
            uint minValue;          // in ether
            address onlySellTo;
        }
        struct Bid {
            bool hasBid;
            uint phunkIndex;
            address bidder;
            uint value;
        }
        // A record of phunks that are offered for sale at a specific minimum value, and perhaps to a specific person
        mapping (uint => Offer) public phunksOfferedForSale;
        // A record of the highest phunk bid
        mapping (uint => Bid) public phunkBids;
        // A record of pending ETH withdrawls by address
        mapping (address => uint) public pendingWithdrawals;
        event PhunkOffered(uint indexed phunkIndex, uint minValue, address indexed toAddress);
        event PhunkBidEntered(uint indexed phunkIndex, uint value, address indexed fromAddress);
        event PhunkBidWithdrawn(uint indexed phunkIndex, uint value, address indexed fromAddress);
        event PhunkBought(uint indexed phunkIndex, uint value, address indexed fromAddress, address indexed toAddress);
        event PhunkNoLongerForSale(uint indexed phunkIndex);
        /* Initializes contract with an instance of CryptoPhunks contract, and sets deployer as owner */
        constructor(address initialPhunksAddress) {
            IERC721(initialPhunksAddress).balanceOf(address(this));
            phunksContract = IERC721(initialPhunksAddress);
        }
        function pause() public whenNotPaused onlyOwner {
            _pause();
        }
        function unpause() public whenPaused onlyOwner {
            _unpause();
        }
        /* Returns the CryptoPhunks contract address currently being used */
        function phunksAddress() public view returns (address) {
          return address(phunksContract);
        }
        /* Allows the owner of the contract to set a new CryptoPhunks contract address */
        function setPhunksContract(address newPhunksAddress) public onlyOwner {
          phunksContract = IERC721(newPhunksAddress);
        }
        /* Allows the owner of a CryptoPhunks to stop offering it for sale */
        function phunkNoLongerForSale(uint phunkIndex) public nonReentrant() {
            if (phunkIndex >= 10000) revert('token index not valid');
            if (phunksContract.ownerOf(phunkIndex) != msg.sender) revert('you are not the owner of this token');
            phunksOfferedForSale[phunkIndex] = Offer(false, phunkIndex, msg.sender, 0, address(0x0));
            emit PhunkNoLongerForSale(phunkIndex);
        }
        /* Allows a CryptoPhunk owner to offer it for sale */
        function offerPhunkForSale(uint phunkIndex, uint minSalePriceInWei) public whenNotPaused nonReentrant()  {
            if (phunkIndex >= 10000) revert('token index not valid');
            if (phunksContract.ownerOf(phunkIndex) != msg.sender) revert('you are not the owner of this token');
            phunksOfferedForSale[phunkIndex] = Offer(true, phunkIndex, msg.sender, minSalePriceInWei, address(0x0));
            emit PhunkOffered(phunkIndex, minSalePriceInWei, address(0x0));
        }
        /* Allows a CryptoPhunk owner to offer it for sale to a specific address */
        function offerPhunkForSaleToAddress(uint phunkIndex, uint minSalePriceInWei, address toAddress) public whenNotPaused nonReentrant() {
            if (phunkIndex >= 10000) revert();
            if (phunksContract.ownerOf(phunkIndex) != msg.sender) revert('you are not the owner of this token');
            phunksOfferedForSale[phunkIndex] = Offer(true, phunkIndex, msg.sender, minSalePriceInWei, toAddress);
            emit PhunkOffered(phunkIndex, minSalePriceInWei, toAddress);
        }
        
        /* Allows users to buy a CryptoPhunk offered for sale */
        function buyPhunk(uint phunkIndex) payable public whenNotPaused nonReentrant() {
            if (phunkIndex >= 10000) revert('token index not valid');
            Offer memory offer = phunksOfferedForSale[phunkIndex];
            if (!offer.isForSale) revert('phunk is not for sale'); // phunk not actually for sale
            if (offer.onlySellTo != address(0x0) && offer.onlySellTo != msg.sender) revert();                
            if (msg.value != offer.minValue) revert('not enough ether');          // Didn't send enough ETH
            address seller = offer.seller;
            if (seller == msg.sender) revert('seller == msg.sender');
            if (seller != phunksContract.ownerOf(phunkIndex)) revert('seller no longer owner of phunk'); // Seller no longer owner of phunk
            phunksOfferedForSale[phunkIndex] = Offer(false, phunkIndex, msg.sender, 0, address(0x0));
            phunksContract.safeTransferFrom(seller, msg.sender, phunkIndex);
            pendingWithdrawals[seller] += msg.value;
            emit PhunkBought(phunkIndex, msg.value, seller, msg.sender);
            // Check for the case where there is a bid from the new owner and refund it.
            // Any other bid can stay in place.
            Bid memory bid = phunkBids[phunkIndex];
            if (bid.bidder == msg.sender) {
                // Kill bid and refund value
                pendingWithdrawals[msg.sender] += bid.value;
                phunkBids[phunkIndex] = Bid(false, phunkIndex, address(0x0), 0);
            }
        }
        /* Allows users to retrieve ETH from sales */
        function withdraw() public nonReentrant() {
            uint amount = pendingWithdrawals[msg.sender];
            // Remember to zero the pending refund before
            // sending to prevent re-entrancy attacks
            pendingWithdrawals[msg.sender] = 0;
            payable(msg.sender).transfer(amount);
        }
        /* Allows users to enter bids for any CryptoPhunk */
        function enterBidForPhunk(uint phunkIndex) payable public whenNotPaused nonReentrant() {
            if (phunkIndex >= 10000) revert('token index not valid');
            if (phunksContract.ownerOf(phunkIndex) == msg.sender) revert('you already own this phunk');
            if (msg.value == 0) revert('cannot enter bid of zero');
            Bid memory existing = phunkBids[phunkIndex];
            if (msg.value <= existing.value) revert('your bid is too low');
            if (existing.value > 0) {
                // Refund the failing bid
                pendingWithdrawals[existing.bidder] += existing.value;
            }
            phunkBids[phunkIndex] = Bid(true, phunkIndex, msg.sender, msg.value);
            emit PhunkBidEntered(phunkIndex, msg.value, msg.sender);
        }
        /* Allows CryptoPhunk owners to accept bids for their Phunks */
        function acceptBidForPhunk(uint phunkIndex, uint minPrice) public whenNotPaused nonReentrant() {
            if (phunkIndex >= 10000) revert('token index not valid');
            if (phunksContract.ownerOf(phunkIndex) != msg.sender) revert('you do not own this token');
            address seller = msg.sender;
            Bid memory bid = phunkBids[phunkIndex];
            if (bid.value == 0) revert('cannot enter bid of zero');
            if (bid.value < minPrice) revert('your bid is too low');
            address bidder = bid.bidder;
            if (seller == bidder) revert('you already own this token');
            phunksOfferedForSale[phunkIndex] = Offer(false, phunkIndex, bidder, 0, address(0x0));
            uint amount = bid.value;
            phunkBids[phunkIndex] = Bid(false, phunkIndex, address(0x0), 0);
            phunksContract.safeTransferFrom(msg.sender, bidder, phunkIndex);
            pendingWithdrawals[seller] += amount;
            emit PhunkBought(phunkIndex, bid.value, seller, bidder);
        }
        /* Allows bidders to withdraw their bids */
        function withdrawBidForPhunk(uint phunkIndex) public nonReentrant() {
            if (phunkIndex >= 10000) revert('token index not valid');
            Bid memory bid = phunkBids[phunkIndex];
            if (bid.bidder != msg.sender) revert('the bidder is not message sender');
            emit PhunkBidWithdrawn(phunkIndex, bid.value, msg.sender);
            uint amount = bid.value;
            phunkBids[phunkIndex] = Bid(false, phunkIndex, address(0x0), 0);
            // Refund the bid money
            payable(msg.sender).transfer(amount);
        }
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "../../utils/introspection/IERC165.sol";
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes calldata data
        ) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    abstract contract ReentrancyGuard {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant _NOT_ENTERED = 1;
        uint256 private constant _ENTERED = 2;
        uint256 private _status;
        constructor() {
            _status = _NOT_ENTERED;
        }
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and make it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            // On the first call to nonReentrant, _notEntered will be true
            require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
            // Any calls to nonReentrant after this point will fail
            _status = _ENTERED;
            _;
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            _status = _NOT_ENTERED;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @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;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }