Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0x3638A3e2dfB3948597AD18B5dadeb0282501bBEd
Balance 0 ETH
Nonce 1
Code Size 2858 bytes
Indexed Transactions 0 (1 on-chain, 0% indexed)
External Etherscan · Sourcify

Contract Bytecode

2858 bytes
0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80638cfa83e51161005b5780638cfa83e5146100ec578063a165527814610103578063a778adde14610118578063b13ca5f71461012b57600080fd5b80634ab37a711461008257806385fba364146100975780638a72ea6a146100aa575b600080fd5b610095610090366004610999565b61016a565b005b6100956100a53660046109bb565b6103d4565b6100bd6100b83660046109ee565b610609565b604080516001600160a01b03909416845261ffff92831660208501529116908201526060015b60405180910390f35b6100f561138881565b6040519081526020016100e3565b61010b610640565b6040516100e39190610a07565b6100956101263660046109bb565b6106bb565b6101527f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca681565b6040516001600160a01b0390911681526020016100e3565b7f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca660008061ffff841661138981106101a4576101a4610a64565b6040805160608101825292909101546001600160a01b03811680845261ffff600160a01b830481166020860152600160b01b90920490911691830191909152909150331480159061026d575080516040516331a9108f60e11b815261ffff851660048201526001600160a01b0391821691841690636352211e90602401602060405180830381865afa15801561023e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102629190610a7a565b6001600160a01b0316145b80156102e75750805160405163e985e9c560e01b81526001600160a01b0391821660048201523060248201529083169063e985e9c590604401602060405180830381865afa1580156102c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102e79190610aa3565b801561037e5750604081015161ffff16158061037e575060408181015190516331a9108f60e11b815261ffff909116600482015233906001600160a01b03841690636352211e90602401602060405180830381865afa15801561034e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103729190610a7a565b6001600160a01b031614155b1561039b576040516282b42960e81b815260040160405180910390fd5b600080845560405161ffff85169133917f899cab278284ae4a91172caa0943607a0bcb19766254c3ebe1139be00650b1029190a3505050565b7f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca660008061ffff8516611389811061040e5761040e610a64565b6040805160608101825292909101546001600160a01b03811680845261ffff600160a01b830481166020860152600160b01b909204909116918301919091529091501580610462575061046084610884565b155b15610480576040516305995b5360e41b815260040160405180910390fd5b604081015161ffff16158015906104a35750806040015161ffff168361ffff1614155b156104c15760405163e4989c3d60e01b815260040160405180910390fd5b6104ca83610884565b6104e75760405163166b6e5960e01b815260040160405180910390fd5b8261ffff168461ffff167f19e358413b77c4e90878dfd18da749fa4208a97d4bbd4598d699d6ba1b57fa7060405160405180910390a36000845580516040516323b872dd60e01b81523360048201526001600160a01b03918216602482015261ffff85166044820152908316906323b872dd90606401600060405180830381600087803b15801561057757600080fd5b505af115801561058b573d6000803e3d6000fd5b5050825160208401516040516323b872dd60e01b81526001600160a01b03928316600482015233602482015261ffff909116604482015290851692506323b872dd9150606401600060405180830381600087803b1580156105eb57600080fd5b505af11580156105ff573d6000803e3d6000fd5b5050505050505050565b600081611389811061061a57600080fd5b01546001600160a01b038116915061ffff600160a01b8204811691600160b01b90041683565b610648610940565b60408051620271208101909152600061138981835b828210156106b25760408051606081018252838601546001600160a01b038116825261ffff600160a01b82048116602080850191909152600160b01b909204169282019290925282526001909201910161065d565b50505050905090565b7f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66106e583610884565b1580610705575061ffff821615801590610705575061070382610884565b155b156107235760405163166b6e5960e01b815260040160405180910390fd5b6040516331a9108f60e11b815261ffff8416600482015233906001600160a01b03831690636352211e90602401602060405180830381865afa15801561076d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107919190610a7a565b6001600160a01b0316146107b7576040516282b42960e81b815260040160405180910390fd5b6040518060600160405280336001600160a01b031681526020018461ffff1681526020018361ffff1681525060008461ffff1661138981106107fb576107fb610a64565b825191018054602084015160409485015161ffff908116600160b01b0261ffff60b01b19928216600160a01b026001600160b01b03199094166001600160a01b0390961695909517929092171692909217905590518382169185169033907fe899a6e29fab942958a400b4db4c5dec136446a7966a69e0011735027a33fff390600090a4505050565b60405161ffff821660248201526000906001600160a01b037f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6169060440160408051601f198184030181529181526020820180516001600160e01b03166331a9108f60e11b179052516108f79190610ac5565b600060405180830381855afa9150503d8060008114610932576040519150601f19603f3d011682016040523d82523d6000602084013e610937565b606091505b50909392505050565b60405180620271200160405280611389905b60408051606081018252600080825260208083018290529282015282526000199092019101816109525790505090565b803561ffff8116811461099457600080fd5b919050565b6000602082840312156109ab57600080fd5b6109b482610982565b9392505050565b600080604083850312156109ce57600080fd5b6109d783610982565b91506109e560208401610982565b90509250929050565b600060208284031215610a0057600080fd5b5035919050565b620753608101818360005b611389811015610a5b57815180516001600160a01b0316845260208082015161ffff90811682870152604092830151169185019190915260609093019290910190600101610a12565b50505092915050565b634e487b7160e01b600052603260045260246000fd5b600060208284031215610a8c57600080fd5b81516001600160a01b03811681146109b457600080fd5b600060208284031215610ab557600080fd5b815180151581146109b457600080fd5b6000825160005b81811015610ae65760208186018101518583015201610acc565b50600092019182525091905056fea2646970667358221220678679a7db9bb77c812fcae7781b11a0c068743fdacf8d5e934a1e214859989964736f6c63430008100033

Verified Source Code Full Match

Compiler: v0.8.16+commit.07a7930e EVM: london Optimization: Yes (200 runs)
NononSwap.sol 130 lines
// SPDX-License-Identifier: MIT

/// @title nonon swap

pragma solidity 0.8.16;

import "./interfaces/INonon.sol";

// errors
error Unauthorized();
error OfferForNonexistentToken();
error NoActiveOffer();
error NotRequestedToken();
error TokenHasExistingOffer();

// state
struct TokenOffer {
    address owner;
    uint16 ownedId;
    uint16 wantedId; // unset (zero) is considered to be open
}

contract NononSwap {
    uint256 public constant nononMaxSupply = 5000;
    address public immutable nononAddress;

    // events
    event OfferCreated(address indexed owner, uint256 indexed ownedId, uint256 indexed wantedId);
    event OfferCancelled(address indexed owner, uint256 indexed ownedId);
    event SwapCompleted(uint256 indexed firstTokenId, uint256 indexed secondTokenId);

    /**
     * @dev Mapping (implemented as an array for gas efficiency) between token
     * ids and token offers. Thus, `offers[0]` should never be defined.
     */
    TokenOffer[nononMaxSupply + 1] public offers;

    constructor(address _nononAddress) {
        nononAddress = _nononAddress;
    }

    /**
     * @dev Create a token swap offer for the owned token `_ownedId` and the
     * wanted token `_wantedId`. It can also be used to update already set
     * offers so the owner doenst need to call `removeOffer` every time they
     * want to change their offer.
     * @param _ownedId Token that `msg.sender` owns and wants to swap for
     * `_wantedId`
     * @param _wantedId Token that `msg.sender` wants, 0 if they dont care
     * and just want to farm friendship points.
     */
    function createTokenOffer(uint16 _ownedId, uint16 _wantedId) external {
        INonon nonon = INonon(nononAddress);

        if (!nononExists(_ownedId) || (_wantedId != 0 && !nononExists(_wantedId))) {
            revert OfferForNonexistentToken();
        }

        if (nonon.ownerOf(_ownedId) != msg.sender) {
            revert Unauthorized();
        }

        offers[_ownedId] = TokenOffer({owner: msg.sender, ownedId: _ownedId, wantedId: _wantedId});

        emit OfferCreated(msg.sender, _ownedId, _wantedId);
    }

    function completeTokenOffer(uint16 _offerTokenId, uint16 _swapId) external {
        INonon nonon = INonon(nononAddress);

        TokenOffer memory offer = offers[_offerTokenId];

        if (offer.owner == address(0) || !nononExists(_offerTokenId)) {
            revert NoActiveOffer();
        }

        if (offer.wantedId != 0 && _swapId != offer.wantedId) {
            revert NotRequestedToken();
        }

        if (!nononExists(_swapId)) {
            revert OfferForNonexistentToken();
        }

        emit SwapCompleted(_offerTokenId, _swapId);

        assembly {
            sstore(add(offers.slot, _offerTokenId), 0)
        }

        // transfer tokens
        nonon.transferFrom(msg.sender, offer.owner, _swapId);
        nonon.transferFrom(offer.owner, msg.sender, offer.ownedId);
    }

    function removeOffer(uint16 _tokenId) external {
        INonon nonon = INonon(nononAddress);

        TokenOffer memory offer = offers[_tokenId];

        // allow removal (aka: dont revert) in one of these cases:
        // - the user is the creator of the offer OR
        // - the offer creator no longer owns the offer token OR
        // - the swap contract does not have approval to transfer nonons on behalf of owner OR
        // - msg.sender is the owner of offer.wantedId
        // if none of these conditions are met (inverses are all true), revert
        if (
            offer.owner != msg.sender // User is not the creator of the offer
                && nonon.ownerOf(_tokenId) == offer.owner // Offer creator still owns the token
                && nonon.isApprovedForAll(offer.owner, address(this)) // Contract is approved
                && (offer.wantedId == 0 || nonon.ownerOf(offer.wantedId) != msg.sender) // No wantedId or user does not own the wantedId
        ) {
            revert Unauthorized();
        }

        assembly {
            sstore(add(offers.slot, _tokenId), 0)
        }

        emit OfferCancelled(msg.sender, _tokenId);
    }

    function nononExists(uint16 tokenId) internal view returns (bool success) {
        (success,) = nononAddress.staticcall(abi.encodeWithSignature("ownerOf(uint256)", tokenId));
    }

    function getAllOffers() external view returns (TokenOffer[nononMaxSupply + 1] memory) {
        return offers;
    }
}
INonon.sol 9 lines
// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.16;

import "ERC721A/IERC721A.sol";

interface INonon is IERC721A {
    function exists(uint256 _tokenId) external view returns (bool);
}
IERC721A.sol 282 lines
// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs

pragma solidity ^0.8.4;

/**
 * @dev Interface of ERC721A.
 */
interface IERC721A {
    /**
     * The caller must own the token or be an approved operator.
     */
    error ApprovalCallerNotOwnerNorApproved();

    /**
     * The token does not exist.
     */
    error ApprovalQueryForNonexistentToken();

    /**
     * Cannot query the balance for the zero address.
     */
    error BalanceQueryForZeroAddress();

    /**
     * Cannot mint to the zero address.
     */
    error MintToZeroAddress();

    /**
     * The quantity of tokens minted must be more than zero.
     */
    error MintZeroQuantity();

    /**
     * The token does not exist.
     */
    error OwnerQueryForNonexistentToken();

    /**
     * The caller must own the token or be an approved operator.
     */
    error TransferCallerNotOwnerNorApproved();

    /**
     * The token must be owned by `from`.
     */
    error TransferFromIncorrectOwner();

    /**
     * Cannot safely transfer to a contract that does not implement the
     * ERC721Receiver interface.
     */
    error TransferToNonERC721ReceiverImplementer();

    /**
     * Cannot transfer to the zero address.
     */
    error TransferToZeroAddress();

    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * The `quantity` minted with ERC2309 exceeds the safety limit.
     */
    error MintERC2309QuantityExceedsLimit();

    /**
     * The `extraData` cannot be set on an unintialized ownership slot.
     */
    error OwnershipNotInitializedForExtraData();

    // =============================================================
    //                            STRUCTS
    // =============================================================

    struct TokenOwnership {
        // The address of the owner.
        address addr;
        // Stores the start time of ownership with minimal overhead for tokenomics.
        uint64 startTimestamp;
        // Whether the token has been burned.
        bool burned;
        // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
        uint24 extraData;
    }

    // =============================================================
    //                         TOKEN COUNTERS
    // =============================================================

    /**
     * @dev Returns the total number of tokens in existence.
     * Burned tokens will reduce the count.
     * To get the total number of tokens minted, please see {_totalMinted}.
     */
    function totalSupply() external view returns (uint256);

    // =============================================================
    //                            IERC165
    // =============================================================

    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    // =============================================================
    //                            IERC721
    // =============================================================

    /**
     * @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,
        bytes calldata data
    ) external payable;

    /**
     * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external payable;

    /**
     * @dev Transfers `tokenId` 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 payable;

    /**
     * @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 payable;

    /**
     * @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 the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @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);

    // =============================================================
    //                        IERC721Metadata
    // =============================================================

    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);

    // =============================================================
    //                           IERC2309
    // =============================================================

    /**
     * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
     * (inclusive) is transferred from `from` to `to`, as defined in the
     * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
     *
     * See {_mintERC2309} for more details.
     */
    event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}

Read Contract

getAllOffers 0xa1655278 → tuple[5001]
nononAddress 0xb13ca5f7 → address
nononMaxSupply 0x8cfa83e5 → uint256
offers 0x8a72ea6a → address, uint16, uint16

Write Contract 3 functions

These functions modify contract state and require a wallet transaction to execute.

completeTokenOffer 0x85fba364
uint16 _offerTokenId
uint16 _swapId
createTokenOffer 0xa778adde
uint16 _ownedId
uint16 _wantedId
removeOffer 0x4ab37a71
uint16 _tokenId

Recent Transactions

This address has 1 on-chain transactions, but only 0% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →