{"id":"ERC-5528","name":"Refundable Fungible Token","status":"Final","chain":"both","category":{"id":"security","name":"Security & Trust","description":"Helping users verify, control, and protect their assets"},"journeyStages":[{"id":"status","name":"Status & Confirmation","description":"Waiting for and confirming outcomes"},{"id":"management","name":"Asset Management","description":"Managing assets over time"}],"uxImpact":"ERC-5528 defines escrow refund and withdrawal interfaces for token sales; it does not guarantee full refunds or prevent every rug pull. The deployed escrow's conditions, refund rate, eligibility, and caller requirements determine what the user can claim.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-5528","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-5528","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-5528","type":"official-spec"}],"lastReviewed":"2026-09-18","specConstraints":[{"id":"payable-contract-erc20-interface","constraint":"The Payable Contract must override the EIP-20 interfaces.","appliesTo":"account-implementation","normativity":"normative","specQuote":"*Payable Contract*: The sellers and buyers use this token to fund the *Escrow Contract*. This contract MUST override [EIP-20](./eip-20.md) interfaces.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#specification","designImplication":"Treat the payable token adapter as an EIP-20-compatible surface and show the escrow relationship before asking a user to fund it."},{"id":"escrow-policy-identities","constraint":"The Escrow Contract must define seller-token and buyer-token contract addresses as policies.","appliesTo":"account-implementation","normativity":"normative","specQuote":"The *Escrow Contract* MUST define the following policies:\n\n- Seller token contract address\n- Buyer token contract address","specSection":"Specification / Methods / constructor","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#constructor","designImplication":"Identify both sides of the exchange and their contract addresses in the contribution and settlement views instead of presenting an escrow as an untyped balance."},{"id":"escrow-policy-options","constraint":"An Escrow Contract MAY define additional policies for period, investor or token limits, exchange rates, and KYC verification.","appliesTo":"account-implementation","normativity":"normative","specQuote":"The *Escrow Contract* MAY define the following policies:\n\n- Escrow period\n- Maximum (or minimum) number of investors\n- Maximum (or minimum) number of tokens to fund\n- Exchange rates of seller/buyer token\n- KYC verification of users","specSection":"Specification / Methods / constructor","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#constructor","designImplication":"Show each configured escrow policy when present, including period, limits, exchange rate, or KYC gate, and do not imply that an escrow has policies the selected contract does not expose."},{"id":"escrow-fund-roles","constraint":"Escrow funding must target the user, come from the Payable Contract, and pass the escrow's policy validations.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- `_to` MUST be the user address.\n - `msg.sender` MUST be the *Payable Contract* address.\n - MUST check policy validations.","specSection":"Specification / Methods / escrowFund","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#escrowfund","designImplication":"Show the receiving user and the escrow policy state before treating a contribution as credited, and distinguish a rejected funding attempt from a completed contribution."},{"id":"payable-fund-forwarding","constraint":"The Payable Contract must forward escrowFund to the Escrow Contract with the caller as the user address.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- The address `_to` MUST be the *Escrow Contract* address.\n\n  - MUST call the same function of the *Escrow Contract* interface. The parameter `_to` MUST be `msg.sender` to recognize the user address in the *Escrow Contract*.","specSection":"Specification / Methods / escrowFund","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#escrowfund","designImplication":"Attribute a contribution to the initiating user and escrow contract only after the adapter's forwarding path has succeeded; do not infer credit from a token approval alone."},{"id":"escrow-refund-roles","constraint":"Escrow refunds must target the user, come from the Payable Contract, and pass the escrow's policy validations.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- `_from` MUST be the user address.\n - `msg.sender` MUST be the *Payable Contract* address.\n - MUST check policy validations.","specSection":"Specification / Methods / escrowRefund","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#escrowrefund","designImplication":"Show refund eligibility and the user whose funds are being returned only after the escrow policy check succeeds."},{"id":"payable-refund-forwarding","constraint":"The Payable Contract must forward escrowRefund to the Escrow Contract with the caller as the user address.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- The address `_from` MUST be the *Escrow Contract* address.\n\n  - MUST call the same function of the *Escrow Contract* interface. The parameter `_from` MUST be `msg.sender` to recognize the user address in the *Escrow Contract*.","specSection":"Specification / Methods / escrowRefund","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#escrowrefund","designImplication":"Keep the refund recipient and forwarding path explicit in confirmation and receipts so a caller cannot mistake an adapter call for a refund to an arbitrary account."},{"id":"escrow-withdraw-settlement","constraint":"The Escrow Contract may withdraw only after the escrow process is complete and must send both remaining token balances to the caller's contract wallets.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- MUST check the escrow process is completed.\n - MUST send the remaining balance of seller and buyer tokens to `msg.sender`'s seller and buyer contract wallets.","specSection":"Specification / Methods / escrowWithdraw","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#escrowwithdraw","designImplication":"Gate settlement UI on an observed completed state and show both token outcomes, including the destination wallets, rather than presenting withdrawal as an unconditional claim."},{"id":"payable-escrow-withdraw-option","constraint":"The Payable Contract's escrowWithdraw method is OPTIONAL.","appliesTo":"account-implementation","normativity":"normative","specQuote":"In the case of *Payable Contract*, it is optional.","specSection":"Specification / Methods / escrowWithdraw","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#escrowwithdraw","designImplication":"Feature-detect escrowWithdraw on the Payable Contract and hide or disable unsupported settlement actions instead of assuming the adapter provides them."},{"id":"payable-contract-backwards-compatibility","constraint":"A Payable Contract implementing this EIP remains backward compatible with EIP-20.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"The *Payable Contract* which implements this EIP is fully backward compatible with the [EIP-20](./eip-20.md) specification.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#backwards-compatibility","designImplication":"Reuse ordinary EIP-20 token identity and balance conventions in the funding flow while labeling escrowed funds separately from spendable balance."},{"id":"escrow-contract-loss-boundary","constraint":"Flaws in an Escrow Contract can cause unexpected behavior and potential loss of funds because it controls seller and buyer rights.","appliesTo":"application","normativity":"security-considerations","specQuote":"Since the *Escrow Contract* controls seller and buyer rights, flaws within the *Escrow Contract* will directly lead to unexpected behavior and potential loss of funds.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-5528#security-considerations","designImplication":"Show the deployed escrow address, policy state, and risk disclosure before contribution; never imply that the interface alone guarantees a refund or safe settlement."}],"lastUpdated":"2026-09-18","summary":"ERC-5528 defines escrow refund and withdrawal interfaces for token sales; it does not guarantee full refunds or prevent every rug pull. The deployed escrow's conditions, refund rate, eligibility, and caller requirements determine what the user can claim.","designerTakeaways":["Show the escrow state and the contract-reported refundable amount separately from spendable balance.","Query refund eligibility and amount before showing a Claim refund action.","Explain the sale's implementation-specific release and refund conditions instead of promising full recovery."],"applicability":{"whenToUse":["Token launches use on-chain escrow with conditional release.","Buyers need protection when sale outcome is uncertain.","Your UI surfaces crowd-sale or IDO participation."],"whenToAvoid":["The sale does not implement the escrow refund/withdraw interfaces.","The product cannot query implementation-specific refund eligibility, amount, and caller requirements.","The UX requires a universal full-refund or rug-pull guarantee that the deployed escrow does not provide."]},"prototypeFirst":[{"screen":"Sale escrow dashboard","why":"Contributors check status repeatedly during a live sale.","covers":["Funded","Running","Cap reached"],"include":["Status pill","Locked amount","Timeline","Your contribution row"]},{"screen":"Failed sale refund","why":"The refund moment is when trust is won or lost.","covers":["Failed state","Refund available","Refund claimed"],"include":["Plain-language failure reason","Claim refund CTA","Amount returned"]},{"screen":"Successful settlement","why":"Users must see tokens received and escrow released.","covers":["Success","Token delivery","Escrow closed"],"include":["Tokens received summary","Escrow released badge","Explorer link"]},{"screen":"Contribution during lock","why":"New buyers need to understand funds are not immediately spendable.","covers":["Active lock","Check available refund and withdrawal actions"],"include":["Funds held in escrow copy","Release conditions","No panic empty-wallet state"]}],"mentalModel":[{"label":"Contribution","description":"User sends funds into escrow — they do not own tokens yet, they own a claim."},{"label":"Escrow lock","description":"Funds remain in escrow until the implementation permits release or a caller can claim a contract-reported refund; failure does not guarantee automatic return."},{"label":"Success path","description":"Sale completes → tokens mint or transfer → escrow releases to project."},{"label":"Failure path","description":"When the implementation reports a refundable state, show the contract-reported amount and the action needed to claim it; do not promise a full contribution refund by standard default."},{"label":"State machine","description":"Funded, Running, Success, Failed are user-visible milestones, not internal enum names."}],"statesToDesign":[{"state":"Escrow funded — sale open","trigger":"User contributed; sale still accepting.","userNeed":"Know funds are held under the escrow contract's release and refund rules.","designResponse":"Show locked amount with Running status and sale end time."},{"state":"Awaiting outcome","trigger":"Sale closed; settlement pending.","userNeed":"Understand where funds are held and which release or refund conditions remain unresolved.","designResponse":"Show the observed escrow state and a timing estimate only when the implementation provides a reliable basis."},{"state":"Success — tokens received","trigger":"Observed token delivery and escrow settlement meet the sale's success conditions.","userNeed":"See tokens and closed escrow.","designResponse":"Success card with token balance and escrow released note."},{"state":"Failed — refund available","trigger":"Sale failed conditions.","userNeed":"Know the contract-reported amount and how to claim it.","designResponse":"Show eligibility, amount, caller requirements, and Claim refund only when the contract allows it."},{"state":"Refund claimed","trigger":"User reclaimed escrow.","userNeed":"Confirm funds returned.","designResponse":"Completed refund receipt with amount and timestamp."}],"designDecisions":[{"question":"How much escrow complexity to expose?","recommendation":"Summarize the actual sale states and available refund/release paths. Keep contract and authority details accessible before contribution.","rationale":"Contributors need confidence, not Solidity architecture."},{"question":"Should locked funds appear in wallet balance?","recommendation":"Show separate Escrowed line item, not merged with spendable balance.","rationale":"Merged balances cause panic sends and support tickets."},{"question":"How to communicate failed sales?","recommendation":"Lead with the contract-reported refund amount and eligibility, then explain why the sale failed.","rationale":"ERC-5528 exposes escrow operations but does not guarantee a full refund or automatic execution for every implementation."}],"problemsSolved":[{"problem":"Contributors need an escrowed release and refund policy they can inspect","oldWay":"Funds sent directly to team wallet with no recourse","newWay":"Escrow conditions and refund operations are visible before contribution","impact":"critical"},{"problem":"Users think contributed ETH disappeared","oldWay":"Wallet shows lower balance with no explanation","newWay":"Escrowed amount labeled with status and release path","impact":"high"},{"problem":"Failed launches leave contributors stranded","oldWay":"Manual refunds or social pressure on team","newWay":"A contract-reported refund path can be claimed when its conditions and amount permit it","impact":"high"}],"uxPatterns":[{"name":"Escrow Status Timeline","description":"An example token-sale timeline whose states and available actions come from the integrated contract, not a universal ERC-5528 state machine.","components":["StatusTimeline","ContributionCard","LockAmount"],"userFlow":["User contributes","Timeline updates","Outcome resolves","Shows the contract-reported token delivery or available refund path"]},{"name":"Claim Refund Flow","description":"Claim the contract-reported refund when the sale implementation makes it available.","components":["FailedBanner","RefundCTA","ReceiptModal"],"userFlow":["App reads the deployed escrow's refund conditions and caller eligibility","Show the current amount, recipient, and any fees","User confirms a supported refund request","Track transaction execution and show the amount actually returned"]}],"antiPatterns":[{"pattern":"Showing zero balance with no escrow explanation","why":"Users assume funds were stolen","instead":"Separate Escrowed row with status and amount","severity":"critical"},{"pattern":"Hiding failed state behind generic transaction error","why":"Contributors cannot find refund path","instead":"Show the contract-reported refund eligibility and amount with a Claim action when available.","severity":"critical"},{"pattern":"Exposing raw state enum names (FUNDED, RUNNING)","why":"Protocol jargon erodes trust","instead":"Human labels: Sale open, Processing, Complete, Refunded","severity":"high"},{"pattern":"Treating escrow as a safety guarantee","why":"The interface does not establish audit quality, release authority, solvency, or the full amount recoverable.","instead":"Identify the contract, custody and release authority, applicable refund conditions, and verified audit evidence if any.","severity":"critical"}],"vocabulary":[{"use":"Held in escrow","avoid":"Funds held safely","why":"Describe custody without certifying the implementation or promising recovery."},{"use":"Claim your refund","avoid":"Trigger refund()","why":"Action-oriented commerce language."},{"use":"Sale succeeded","avoid":"State SUCCESS","why":"Outcome language, not enum values."}],"technicalNotes":"ERC-5528 defines escrow refund/withdraw interfaces and implementation-defined sale conditions. It does not guarantee full contribution refunds, automatic refund execution, or protection from every rug pull. Query the deployed contract's state, eligibility, amount, and caller requirements.","relatedStandards":[{"id":"ERC-5507","relationship":"Token-type-specific refund interfaces for ERC-20, ERC-721, and ERC-1155."},{"id":"ERC-20","relationship":"Fungible tokens sold through escrow mechanism"}],"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-5528","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-5528","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5528","markdown":"https://www.eipsfordesigners.com/standards/ERC-5528/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5528/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5528","official":"https://ercs.ethereum.org/ERCS/erc-5528","discussion":"https://ethereum-magicians.org/search?q=ERC-5528"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}