{"id":"ERC-6105","name":"No Intermediary NFT Trading","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"ERC-6105 defines a direct NFT listing and purchase path through listItem, delistItem, and buyItem. A deployment may avoid relying on an intermediary trading platform, but the standard does not guarantee zero contract, application, royalty, gas, or other fees; show the target implementation's actual terms.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-6105","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-6105","summary":"ERC-6105 defines a direct NFT listing and purchase path through listItem, delistItem, and buyItem. A deployment may avoid relying on an intermediary trading platform, but the standard does not guarantee zero contract, application, royalty, gas, or other fees; show the target implementation's actual terms.","applicability":{"whenToUse":["The target collection exposes the ERC-6105 direct listing and purchase interface.","The product can show the selected payment token, expiry, royalty, application, and gas terms.","A direct sale path is useful even when optional buyer-specific offer extensions are separate.","You are designing a direct listing interface with visible states and recovery paths."],"whenToAvoid":["The collection does not implement the direct listing and purchase interface.","The flow requires a buyer-specific offer extension the collection does not support.","You need royalties or transfer restrictions enforced across unrelated venues and direct transfers."]},"designerTakeaways":["Design listing UI around tokenId, price, expiry, supported payment token, and the target implementation's configured fees or royalties.","Describe an intermediary-free path as a possible deployment property, not a universal zero-fee promise.","Preview a combined purchase only when the target implementation settles payment and NFT transfer together, and disclose its royalty and transfer conditions."],"problemsSolved":[{"problem":"A collection needs a direct listing path","oldWay":"Rely on a marketplace-specific listing API.","newWay":"Use the target contract's listItem, delistItem, and buyItem path when implemented.","impact":"critical"},{"problem":"Sale terms are scattered across interfaces","oldWay":"Users cannot see expiry, payment token, or configured royalty before signing.","newWay":"Show the actual terms returned by the target listing and royalty paths.","impact":"high"},{"problem":"Peer trades need an explicit settlement path","oldWay":"Send the NFT and payment through separate, trust-dependent actions.","newWay":"Use a deployment that settles the direct purchase path together and disclose any remaining contract, gas, application, or royalty costs.","impact":"high"},{"problem":"Private sale requirements are unclear","oldWay":"Assume the core listing is buyer-restricted.","newWay":"Label buyer-specific collection or item offer extensions separately from core listItem.","impact":"medium"}],"uxPatterns":[{"name":"Direct Listing Interface","description":"List an NFT through the target contract without implying universal fee or royalty terms.","userFlow":["User selects an NFT","Enters price, expiry, and supported payment token","UI loads configured royalty/application/gas terms","User reviews the actual fee breakdown","Creates the on-chain listing"]},{"name":"Private Sale Extension","description":"Use buyer-specific offers only when the selected collection or item extension supports them.","userFlow":["User chooses the supported private-sale path","Enters and confirms the buyer address","UI identifies the extension and its settlement terms","Creates the listing or offer","Buyer sees the verified restriction before purchase"]},{"name":"Direct Purchase Flow","description":"Buy an active listing while showing the target contract's settlement and payment terms.","userFlow":["Buyer opens the listing","Sees NFT, price, expiry, payment token, and configured fees","Reviews any royalty and transfer condition","Submits buyItem when the listing is active","UI confirms settlement after the transaction"]},{"name":"Active Listings Manager","description":"Manage target-contract listings and their actual lifecycle.","userFlow":["Seller views active listings","Checks expiry and target contract","Shows whether delistItem is available","Cancels through the supported call","Relists only after the prior state settles"]}],"uiComponents":[{"name":"DirectListingForm","description":"Create on-chain NFT listing","states":["editing","confirming","listing","listed"],"props":["nft","onList","defaultPrice","showRoyalty"]},{"name":"PrivateSaleConfig","description":"Configure an optional buyer-restricted sale extension or application flow","states":["public","private","validating-address"],"props":["buyerAddress","onBuyerChange","resolved"]},{"name":"DirectPurchaseCard","description":"Purchase UI for on-chain listings","states":["available","expired","sold","purchasing"],"props":["listing","onPurchase","showBreakdown"]},{"name":"ListingManager","description":"Dashboard for managing active listings","states":["loading","has-listings","empty"],"props":["listings","onEdit","onCancel"]}],"antiPatterns":[{"pattern":"Promising a universal zero-fee sale","why":"ERC-6105 does not eliminate contract, gas, application, or configured royalty costs.","instead":"Show the target path's actual payment, royalty, application, and gas terms; describe intermediary avoidance as optional.","severity":"high"},{"pattern":"Claiming a universal marketplace fee baseline","why":"The specification does not establish a 2–5% marketplace rate.","instead":"Compare only against a named, current venue when independently sourced, or omit the comparison.","severity":"high"},{"pattern":"Hiding whether royalties are enforced on this path","why":"A direct sale's royalty behavior and scope depend on the target implementation.","instead":"Show configured royalty information and label where it is enforced.","severity":"high"},{"pattern":"Making private-sale restrictions look core","why":"Core listItem is not buyer-restricted; optional extensions add that behavior.","instead":"Identify the selected buyer-specific extension and its prerequisites.","severity":"medium"},{"pattern":"No confirmation before listing","why":"A wrong price, token, or expiry can create an unintended listing.","instead":"Show all target-contract terms and require explicit confirmation.","severity":"medium"},{"pattern":"Not showing listing expiry","why":"The seller may rely on stale terms.","instead":"Show expiry and the actual delist/relist path.","severity":"medium"}],"specConstraints":[{"id":"listing-creation-requirements","constraint":"A compliant listing contract requires an existing token, an authorized seller, a non-zero sale price, and a valid expiry, and it emits UpdateListing when the listing is created or updated.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Create or update a listing for `tokenId`\n  /// @dev `salePrice` MUST NOT be set to zero\n  /// @param tokenId - identifier of the token being listed\n  /// @param salePrice - the price the token is being sold for\n  /// @param expires - UNIX timestamp, the buyer could buy the token before expires\n  /// @param supportedToken - contract addresses of supported token or zero address\n  ///                         The zero address indicates that the supported token is ETH\n  ///                         Buyer needs to purchase item with supported token\n  /// Requirements:\n  /// - `tokenId` must exist\n  /// - Caller must be owner, authorised operators or approved address of the token\n  /// - `salePrice` must not be zero\n  /// - `expires` must be valid\n  /// - Must emit an {UpdateListing} event.","specSection":"Specification — IERC6105 listing interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Validate token existence, seller authorization, non-zero price, expiry, and supported payment token before submitting a listing. Confirm the resulting state from the UpdateListing event instead of treating a submitted transaction as an active listing."},{"id":"delisting-requirements","constraint":"Delisting requires an existing token that is listed for sale, an owner/operator/approved caller, and an UpdateListing event.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Remove the listing for `tokenId`\n  /// @param tokenId - identifier of the token being delisted\n  /// Requirements:\n  /// - `tokenId` must exist and be listed for sale\n  /// - Caller must be owner, authorised operators or approved address of the token\n  /// - Must emit an {UpdateListing} event","specSection":"Specification — IERC6105 delisting interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Only enable delist for an active listing when the connected account has the required token authority. Refresh the listing state from the resulting UpdateListing event and show a failed or stale state when the preconditions no longer hold."},{"id":"purchase-requirements","constraint":"A direct purchase requires an active listing, matching expected salePrice and supportedToken, the ability to pay, and a Purchased event.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Buy a token and transfer it to the caller\n  /// @dev `salePrice` and `supportedToken` must match the expected purchase price and token to prevent front-running attacks\n  /// @param tokenId - identifier of the token being purchased\n  /// @param salePrice - the price the token is being sold for\n  /// @param supportedToken - contract addresses of supported token or zero address\n  /// Requirements:\n  /// - `tokenId` must exist and be listed for sale\n  /// - `salePrice` must matches the expected purchase price to prevent front-running attacks\n  /// - `supportedToken` must matches the expected purchase token to prevent front-running attacks\n  /// - Caller must be able to pay the listed price for `tokenId`\n  /// - Must emit a {Purchased} event","specSection":"Specification — IERC6105 purchase interface","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Show the active listing's token, price, payment token, and payable amount immediately before purchase. Bind the submitted values to that listing, handle stale or changed terms explicitly, and confirm settlement from the Purchased event."},{"id":"collection-offer-creation","constraint":"The optional collection-offer extension requires enough supported tokens and allowance, non-zero salePrice and amount, a valid expiry, and an UpdateCollectionOffer event.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Create or update an offer for the collection\n  /// @dev `salePrice` MUST NOT be set to zero\n  /// @param amount - the amount the offerer wants to buy at `salePrice` per token\n  /// @param salePrice - the price of each token is being offered for the collection\n  /// @param expires - UNIX timestamp, the offer could be accepted before expires\n  /// @param supportedToken - contract addresses of supported token\n  ///                         Buyer wants to purchase items with supported token\n  /// Requirements:\n  /// - The caller must have enough supported tokens, and has approved the contract a sufficient amount\n  /// - `salePrice` must not be zero\n  /// - `amount` must not be zero\n  /// - `expires` must be valid\n  /// - Must emit an {UpdateCollectionOffer} event","specSection":"Specification — Optional collection offer extension","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Expose collection offers only when the selected deployment supports the optional extension. Before signing, show the supported ERC-20, amount, price, expiry, spender, and allowance or balance failure state."},{"id":"collection-offer-acceptance","constraint":"Accepting a collection offer requires an existing offered token, an owner/operator/approved caller, the expected offer terms, decrementing the remaining amount after completion, and a Purchased event.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Accepts collection offer and transfers the token to the buyer\n  /// @dev `salePrice` and `supportedToken` must match the expected purchase price and token to prevent front-running attacks\n  ///      When the trading is completed, the `amount` of NFTs the buyer wants to purchase needs to be reduced by 1\n  /// @param tokenId - identifier of the token being offered\n  /// @param salePrice - the price the token is being offered for\n  /// @param supportedToken - contract addresses of supported token\n  /// @param buyer - address of who wants to buy the token\n  /// Requirements:\n  /// - `tokenId` must exist and be offered for\n  /// - Caller must be owner, authorised operators or approved address of the token\n  /// - Must emit a {Purchased} event\n  function acceptCollectionOffer(uint256 tokenId, uint256 salePrice, address supportedToken, address buyer) external;\n\n  /// @notice Accepts collection offer and transfers the token to the buyer\n  /// @dev `salePrice` and `supportedToken` must match the expected purchase price and token to prevent front-running attacks\n  ///      When the trading is completed, the `amount` of NFTs the buyer wants to purchase needs to be reduced by 1\n  /// @param tokenId - identifier of the token being offered\n  /// @param salePrice - the price the token is being offered for\n  /// @param supportedToken - contract addresses of supported token\n  /// @param buyer - address of who wants to buy the token\n  /// @param benchmarkPrice - additional price parameter, may be used when calculating royalties\n  /// Requirements:\n  /// - `tokenId` must exist and be offered for\n  /// - Caller must be owner, authorised operators or approved address of the token\n  /// - Must emit a {Purchased} event","specSection":"Specification — Optional collection offer extension","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Show the buyer, price, payment token, remaining collection-offer amount, and any benchmark-price input before acceptance. Reject stale terms, preserve the owner/operator authorization state, and decrement the remaining amount only after settlement."},{"id":"collection-offer-cancellation","constraint":"Only the collection-offer creator can cancel it, and cancellation emits UpdateCollectionOffer.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Removes the offer for the collection\n  /// Requirements:\n  /// - Caller must be the offerer\n  /// - Must emit an {UpdateCollectionOffer} event","specSection":"Specification — Optional collection offer extension","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Show cancel only to the offer creator, and reflect cancellation after the UpdateCollectionOffer event rather than optimistically removing an offer."},{"id":"item-offer-creation","constraint":"The optional item-offer extension requires an existing token, enough supported tokens and allowance, non-zero salePrice, a valid expiry, and an UpdateItemOffer event.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Create or update an offer for `tokenId`\n  /// @dev `salePrice` MUST NOT be set to zero\n  /// @param tokenId - identifier of the token being offered\n  /// @param salePrice - the price the token is being offered for\n  /// @param expires - UNIX timestamp, the offer could be accepted before expires\n  /// @param supportedToken - contract addresses of supported token\n  ///                         Buyer wants to purchase item with supported token\n  /// Requirements:\n  /// - `tokenId` must exist\n  /// - The caller must have enough supported tokens, and has approved the contract a sufficient amount\n  /// - `salePrice` must not be zero\n  /// - `expires` must be valid\n  /// - Must emit an {UpdateItemOffer} event.","specSection":"Specification — Optional item offer extension","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Expose item offers only when the optional extension is supported. Validate token existence, ERC-20 balance and allowance, non-zero price, and expiry, then confirm the resulting offer from UpdateItemOffer."},{"id":"item-offer-cancellation","constraint":"Only the item-offer creator can cancel an offer, and cancellation emits UpdateItemOffer.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Remove the offer for `tokenId`\n  /// @param tokenId - identifier of the token being canceled offer\n  /// Requirements:\n  /// - `tokenId` must exist and be offered for\n  /// - Caller must be the offerer\n  /// - Must emit an {UpdateItemOffer} event","specSection":"Specification — Optional item offer extension","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Show cancel only to the offer creator when the token offer is active, and update the UI from the resulting UpdateItemOffer event."},{"id":"item-offer-acceptance","constraint":"Accepting an item offer requires an existing offered token, the required owner/operator/approved caller, matching offer terms, removing the completed offer, and a Purchased event.","appliesTo":"infrastructure","normativity":"normative","specQuote":"/// @notice Accept offer and transfer the token to the buyer\n  /// @dev `salePrice` and `supportedToken` must match the expected purchase price and token to prevent front-running attacks\n  ///      When the trading is completed, the offer infomation needs to be removed\n  /// @param tokenId - identifier of the token being offered\n  /// @param salePrice - the price the token is being offered for\n  /// @param supportedToken - contract addresses of supported token\n  /// @param buyer - address of who wants to buy the token\n  /// Requirements:\n  /// - `tokenId` must exist and be offered for\n  /// - Caller must be owner, authorised operators or approved address of the token\n  /// - Must emit a {Purchased} event\n  function acceptItemOffer(uint256 tokenId, uint256 salePrice, address supportedToken, address buyer) external;\n\n  /// @notice Accepts offer and transfers the token to the buyer\n  /// @dev `salePrice` and `supportedToken` must match the expected purchase price and token to prevent front-running attacks\n  ///      When the trading is completed, the offer infomation needs to be removed\n  /// @param tokenId - identifier of the token being offered\n  /// @param salePrice - the price the token is being offered for\n  /// @param supportedToken - contract addresses of supported token\n  /// @param buyer - address of who wants to buy the token\n  /// @param benchmarkPrice - additional price parameter, may be used when calculating royalties\n  /// Requirements:\n  /// - `tokenId` must exist and be offered for\n  /// - Caller must be owner, authorised operators or approved address of the token\n  /// - Must emit a {Purchased} event","specSection":"Specification — Optional item offer extension","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Show the offered token, buyer, price, payment token, and any benchmark-price input before acceptance. Keep stale, unauthorized, and already-completed states explicit, and remove the offer only after the Purchased event confirms settlement."},{"id":"erc721-erc2981-compatibility","constraint":"ERC-6105 is compatible with ERC-721 and ERC-2981.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"This standard is compatible with [ERC-721](./eip-721.md) and [ERC-2981](./eip-2981.md).","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Keep ERC-721 ownership and transfer surfaces and ERC-2981 royalty information interoperable. Feature-detect the direct listing interface without replacing the collection's existing token or royalty semantics."},{"id":"purchase-front-running-protection","constraint":"Buy and offer-acceptance flows must check salePrice and supportedToken against expected values to prevent front-running attacks.","appliesTo":"infrastructure","normativity":"security-considerations","specQuote":"The `buyItem` function, as well as the `acceptCollectionOffer` and `acceptItemOffer` functions, has a potential front-running risk.  Must check that `salePrice` and `supportedToken` match the expected price and token to prevent front-running attacks","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Bind purchase and offer-acceptance arguments to the currently displayed listing or offer. Show a clear stale-price or payment-token mismatch state and require a fresh review rather than silently retrying with changed terms."},{"id":"offer-reentrancy-protection","constraint":"Collection- and item-offer acceptance implementations must use checks-effects-interactions or a reentrancy guard.","appliesTo":"infrastructure","normativity":"security-considerations","specQuote":"There is a potential re-entrancy risk with the `acceptCollectionOffer` and `acceptItemOffer` functions. Make sure to obey the checks, effects, interactions pattern or use a reentrancy guard.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Keep offer acceptance pending until the transaction is confirmed and show a recoverable failure state. Do not present a completed transfer or reduced offer amount from an optimistic client transition."},{"id":"erc20-approval-safety","constraint":"An ERC-20 purchase requires buyer approval for an appropriate amount, and non-audited token contracts warrant caution.","appliesTo":"application","normativity":"security-considerations","specQuote":"If a buyer uses [ERC-20](./eip-20.md) tokens to purchase an NFT, the buyer needs to first call the `approve(address spender, uint256 amount)` function of the ERC-20 token to grant the NFT contract access to a certain `amount` of tokens. Please make sure to authorize an appropriate `amount`. Furthermore, caution is advised when dealing with non-audited contracts.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Separate ERC-20 approval and purchase when required, and show the token, spender, exact amount, allowance state, and any audit-status warning before the buyer signs."},{"id":"approval-phishing-risk","constraint":"Collection-wide setApprovalForAll authorization can expose NFT traders to phishing and deceptive low-price orders.","appliesTo":"wallet","normativity":"rationale","specSection":"Motivation","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105#motivation","designImplication":"Explain collection-wide approval scope, show the order recipient and price before signing, and make revocation discoverable.","specQuote":"1. Security concerns arise from authorization via the `setApprovalForAll` function. The permissions granted to NFT trading platforms expose unnecessary risks. Should a problem occur with the trading platform contract, it would result in significant losses to the industry as a whole. Additionally, if a user has authorized the trading platform to handle their NFTs, it allows a phishing scam to trick the user into signing a message that allows the scammer to place an order at a low price on the NFT trading platform and designate themselves as the recipient. This can be difficult for ordinary users to guard against."},{"id":"benchmark-price-context","constraint":"benchmarkPrice MAY be used when calculating royalties.","appliesTo":"application","normativity":"normative","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105","designImplication":"Show benchmark price separately from sale price and state whether the active royalty calculation uses it.","specQuote":"/// @param benchmarkPrice - Additional price parameter, may be used when calculating royalties"},{"id":"optional-royalty-blocklist","constraint":"Implementations MAY add a blocklist to protect a project's royalty scheme, but ERC-6105 does not provide a standardized blocklist interface.","appliesTo":"application","normativity":"rationale","specSection":"Rationale > Optional Blocklist","specUrl":"https://ercs.ethereum.org/ERCS/erc-6105#optional-blocklist","designImplication":"Disclose when a deployment applies its own blocklist and distinguish that policy from a standard ERC-6105 capability.","specQuote":"Some viewpoints suggest that tokens should be prevented from trading on intermediary markets that do not comply with royalty schemes, but this standard only provides a functionality for non-intermediary NFT trading and does not offer a standardized interface to prevent tokens from trading on these markets. If deemed necessary to better protect the interests of the project team and community, they may consider adding a blocklist to their implementation contracts to prevent NFTs from being traded on platforms that do not comply with the project’s royalty scheme."}],"keyTakeaways":["ERC-6105 provides a direct NFT listing and purchase path when the target collection implements it.","An intermediary-free path does not guarantee zero contract, gas, application, or royalty fees.","Show actual listing, payment, expiry, and royalty terms before signing.","Buyer-specific offers and cross-venue enforcement are separate extensions or application behavior."],"technicalNotes":"ERC-6105 core defines listItem(tokenId, salePrice, expires, supportedToken[, benchmarkPrice]), delistItem(tokenId), buyItem(tokenId, salePrice, supportedToken), and getListing(tokenId). Core listings are not buyer-restricted; collection and item offer extensions add optional buyer-specific flows. The direct buy path can calculate and distribute configured ERC-2981 royalties, but the standard does not provide a standardized blocklist preventing intermediary-market transfers or direct-transfer bypasses.","lastUpdated":"2026-09-18","sources":[{"label":"ERC-6105 official specification","url":"https://ercs.ethereum.org/ERCS/erc-6105","type":"official-spec"}],"lastReviewed":"2026-09-18"},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-6105","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-6105","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-6105","markdown":"https://www.eipsfordesigners.com/standards/ERC-6105/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-6105/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-6105","official":"https://ercs.ethereum.org/ERCS/erc-6105","discussion":"https://ethereum-magicians.org/search?q=ERC-6105"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}