{"id":"ERC-5507","name":"Refundable Tokens","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"ERC-5507 defines refund extensions for ERC-20, ERC-721, and ERC-1155 tokens. This guide focuses on an NFT refund flow. Read the token-specific refund amount and first ineligible block, holdings, and approval requirements. Refund rights are not universally restricted to the original purchaser.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-5507","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-5507","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-5507","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"ERC-5507 defines refund extensions for ERC-20, ERC-721, and ERC-1155 tokens. This guide focuses on an NFT refund flow. Read the token-specific refund amount and first ineligible block, holdings, and approval requirements. Refund rights are not universally restricted to the original purchaser.","designerTakeaways":["Show the contract's predetermined block deadline and current refund terms before purchase.","Query refundDeadlineOf, refundOf, and the implementation's eligibility before offering Claim refund.","Differentiate contract-reported refundable inventory from final-sale or ineligible states."],"applicability":{"whenToUse":["The integrated token implements the relevant ERC-5507 refund extension.","The product can read current refund terms and simulate the actual caller and token amount.","An NFT marketplace needs to explain whether the current holder can refund an item."],"whenToAvoid":["The contract does not implement refundDeadlineOf, refundOf, and the ERC-5507 refund operations.","The product cannot query contract-defined refund amount and eligibility.","A receipt-relative refund window is required but the implementation only exposes a predetermined block deadline."]},"prototypeFirst":[{"screen":"Listing with refund badge","why":"Buyers decide with refund terms visible before they connect a wallet.","covers":["Refund deadline","Final sale vs refundable"],"include":["Refund terms and block deadline chip","Tooltip explaining block-based deadline","Price and CTA"]},{"screen":"Owned item refund request","why":"Users need the current terms and a clear confirmation before returning an owned token.","covers":["Eligible","Expired","Pending refund"],"include":["Contract block deadline","Current eligibility and amount","Claim/refund action when supported","What happens next copy"]},{"screen":"Refund confirmation","why":"Users need certainty about what they lose and regain.","covers":["Success","Reverted","Partial eligibility"],"include":["Item preview","Refund amount","Irreversible warning"]},{"screen":"Marketplace resale with active refund","why":"Resale while refundable creates confusion about who can still return.","covers":["Refundable badge on listing","Transfer during window"],"include":["Current owner and token-specific refund terms","Approval requirement and payout recipient","Ineligible state only when established by the deployed contract"]}],"mentalModel":[{"label":"Purchase moment","description":"The contract exposes a predetermined block deadline; it does not automatically start an individual timer when the buyer receives the token."},{"label":"Refund window","description":"A refund is available only while the deployed contract reports an active block deadline and current eligibility; amount and rights can be implementation-specific."},{"label":"Refund action","description":"A supported refund operation returns the specified value under the token contract rules. Show the token amount or IDs, expected payout, and who receives it."},{"label":"Resale overlap","description":"Re-read the new holder's eligibility after transfer; do not assume buying on a secondary market removes the refund right."},{"label":"Marketplace mirror","description":"Aggregators must read the same on-chain eligibility — badges should match the primary sale site."}],"statesToDesign":[{"state":"Refundable — window open","trigger":"User owns a token and the contract reports an active refund deadline and eligible amount.","userNeed":"Know how long they have and how to return.","designResponse":"Show the contract-reported block deadline, amount, and Claim refund action only when eligible."},{"state":"Refund pending","trigger":"User submitted refund transaction.","userNeed":"Track progress like an order return.","designResponse":"Track submission, inclusion, execution result, and observed payout. Only mark the refund complete when its outcome is verified."},{"state":"Refund window expired","trigger":"The contract's predetermined block deadline has passed or eligibility is false.","userNeed":"Understand that this refund path has expired, without implying that ownership or every other remedy has changed.","designResponse":"Replace the refund action with the contract-reported final or ineligible state; do not infer a receipt-relative window."},{"state":"Non-refundable listing","trigger":"Token or sale type excludes refunds.","userNeed":"Not discover refund option at checkout.","designResponse":"Final sale badge before purchase; no refund CTA in owned view."},{"state":"Refund rejected","trigger":"Contract reverts refund attempt.","userNeed":"Know why return failed.","designResponse":"Show a decoded contract reason when available. Otherwise state that the refund failed and refresh eligibility before retrying."}],"designDecisions":[{"question":"Can a secondary buyer request a refund?","recommendation":"Read current holdings, the token-specific deadline and refund amount, and the deployed authorization policy. Offer the action only when that caller is eligible.","rationale":"The standard does not impose a universal primary-buyer-only rule."},{"question":"How prominent should the countdown be?","recommendation":"Show the first ineligible block and current block. If estimating a wall-clock deadline, label the time as approximate and recheck chain state before submission.","rationale":"RefundDeadlineOf is block-based, not a timer that starts at receipt."},{"question":"What changes after resale?","recommendation":"Refresh ownership and eligibility for the new holder. For refundFrom, identify the authorized caller and payout recipient before requesting approval.","rationale":"A stale ownership check or an unexpected payout recipient can send users down the wrong refund path."}],"problemsSolved":[{"problem":"NFT purchases feel irreversible and risky","oldWay":"Buyers hesitate on expensive mints with no recourse","newWay":"A contract can expose a refund deadline, amount, and eligibility that the UI reads before purchase and return","impact":"high"},{"problem":"Refund rules buried in fine print","oldWay":"Users discover no returns after connecting wallet","newWay":"Badges and countdowns surface policy before payment","impact":"high"},{"problem":"Marketplaces show identical UI for final-sale items","oldWay":"All listings look equally permanent","newWay":"Refundable vs final-sale visual treatment sets expectations","impact":"medium"}],"uxPatterns":[{"name":"Refund Window Badge","description":"Listing chip showing the contract's block deadline and current refund terms before purchase.","components":["RefundBadge","DeadlineTooltip","ListingCard"],"userFlow":["User browses","Sees Refund terms and block deadline","Reads policy","Purchases informed"]},{"name":"Return Request Flow","description":"Return flow that queries current amount and eligibility instead of assuming a receipt-relative window.","components":["CountdownTimer","RefundButton","ConfirmModal"],"userFlow":["User opens owned item","App reads the contract's block deadline and current eligibility","Taps Request Refund","Confirms","Token returned"]}],"antiPatterns":[{"pattern":"Showing Refund button after window expired","why":"Users waste gas on doomed transactions","instead":"Disable the known-expired on-chain refund path and show its block deadline. Do not imply that every legal or off-chain remedy has ended.","severity":"high"},{"pattern":"Hiding refund terms until after mint","why":"Feels like bait-and-switch at checkout","instead":"Badge on listing and confirm step before signature","severity":"critical"},{"pattern":"Identical cards for refundable and final-sale items","why":"Users cannot compare purchase risk","instead":"Distinct badge treatment in grid and detail views","severity":"medium"},{"pattern":"Approving a refund operator without explaining the payout recipient","why":"refundFrom can send the refund to the caller rather than the token holder.","instead":"Show the operator, tokens being returned, approval scope, and Ether recipient before confirmation.","severity":"critical"}],"vocabulary":[{"use":"Refund available until block deadline","avoid":"Refund window epoch","why":"Describes the contract-reported deadline without implying a receipt-relative timer."},{"use":"On-chain refund unavailable","avoid":"No possible refund","why":"Describe the supported contract path without making a broader claim about remedies or buyer rights."},{"use":"Request return","avoid":"Execute refund()","why":"Action language users recognize from retail."}],"specConstraints":[{"id":"batch-refund-atomicity","constraint":"A supported batch refund must succeed or fail as one operation, with no partial refunds.","appliesTo":"application","normativity":"normative","specQuote":"These must either succeed or fail together; there are no partial refunds.","specSection":"Specification / Optional Batch Refund Extensions","specUrl":"https://ercs.ethereum.org/ERCS/erc-5507#optional-erc-721-batch-refund-extension","designImplication":"Preview the entire batch and make the final result all-or-nothing in the interface; do not show individual items as refunded when the batch transaction reverted."},{"id":"refund-order","constraint":"Refund implementations must destroy the refunded tokens before transferring Ether to reduce re-entrancy risk.","appliesTo":"account-implementation","normativity":"security-considerations","specQuote":"There is a potential re-entrancy risk with the `refund` function. Make sure to perform the ether transfer **after** the tokens are destroyed (i.e. obey the checks, effects, interactions pattern).","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-5507#security-considerations","designImplication":"Only present a completed refund after the token burn and payout succeed, and expose a failed or pending state rather than implying that Ether was paid before the asset state changed."},{"id":"batch-refund-optionality","constraint":"Batch refunds are OPTIONAL; when supported, they MAY reduce gas costs alongside account-abstraction-based atomic operations.","appliesTo":"application","normativity":"rationale","specQuote":"Batch refunds are optional, as account abstraction would make atomic operations like these significantly easier. However, they might still reduce gas costs if properly implemented.","specSection":"Rationale","specUrl":"https://ercs.ethereum.org/ERCS/erc-5507#rationale","designImplication":"Gate batch-refund controls on deployed support and present any gas benefit as an option; do not imply that an individual refund requires batching."}],"technicalNotes":"Use the refund interface for the token type: refund and refundFrom, with optional batch operations where implemented. refundDeadlineOf reports the first block where refunding is no longer active. refundFrom sends the Ether payout to its caller, so disclose both whose tokens are returned and who receives funds. Read current holdings, approvals, amount, and eligibility; do not invent refundAll or a universal original-buyer restriction.","relatedStandards":[{"id":"ERC-5528","relationship":"Fungible token escrow refunds complement NFT returns"},{"id":"ERC-721","relationship":"ERC-721 functions are extended with refund views and operations; this is not a generic refund hook or receipt-relative timer."}],"partialDeployment":{"body":"This guide describes an interface-specific integration. A live deployment has not been verified here. Confirm the target contract, network, and client support before offering these actions; Final describes the specification, not product availability."}},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-5507","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-5507","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5507","markdown":"https://www.eipsfordesigners.com/standards/ERC-5507/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5507/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5507","official":"https://ercs.ethereum.org/ERCS/erc-5507","discussion":"https://ethereum-magicians.org/search?q=ERC-5507"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}