{"id":"ERC-5169","name":"Client Script URI (TokenScript)","status":"Final","chain":"both","category":{"id":"comprehension","name":"Comprehension & Display","description":"Making blockchain data readable to humans"},"journeyStages":[{"id":"specialized","name":"Specialized Interactions","description":"Physical items, AI, social, gaming"}],"uxImpact":"ERC-5169 lets token contracts publish script locations for compatible clients. The interface returns an array of URIs; it does not mandate TokenScript or universal wallet support. Clients must check authenticity, supported format and execution permissions before exposing script-driven actions.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-5169","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-5169","sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-5169","type":"official-spec"}],"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","summary":"ERC-5169 lets token contracts publish script locations for compatible clients. The interface returns an array of URIs; it does not mandate TokenScript or universal wallet support. Clients must check authenticity, supported format and execution permissions before exposing script-driven actions.","designerTakeaways":["Show scriptURI-linked actions only after the selected client verifies a supported source and format.","Expose script source, integrity state, and capability limits before a script-built contract action.","Require explicit consent for each action and keep a built-in fallback when script support is unavailable."],"applicability":{"whenToUse":["A token exposes scriptURI and the selected client supports a script format and execution policy.","The product can show source, integrity, capabilities, consent, and failure states before exposing actions.","The client can isolate script execution and constrain its capabilities."],"whenToAvoid":["Token actions are fully covered by built-in wallet features.","Script trust model cannot be explained to users.","Security review cannot vet linked scripts."]},"prototypeFirst":[{"screen":"Verified script action","why":"Prove the selected client can discover, verify, and explain a supported script before exposing its action.","covers":["Verified source","Clear action summary"],"include":["Source and integrity details","Consent step","Result or fallback"]},{"screen":"Unsupported or unverified script","why":"The interface must explain when the client cannot safely execute the selected format or source.","covers":["Unsupported format","Integrity or source failure"],"include":["Plain-language reason","Fallback action"]},{"screen":"Script failure recovery","why":"A script can fail before execution, during a contract call, or after the user rejects it.","covers":["Verification failure","Contract revert"],"include":["Retry path","Support context"]},{"screen":"Source and capability disclosure","why":"Users and reviewers need to understand where an action came from and what it can do.","covers":["Script URI","Integrity metadata","Capability policy"],"include":["Expandable section","Copy buttons","Explorer link"]}],"mentalModel":[{"label":"Token script link","description":"scriptURI() returns an array of script URIs. TokenScript is one possible client-supported format, not the format mandated by this standard."},{"label":"Discovery","description":"A supporting wallet or app selects a supported script format, verifies the source and integrity, and only then offers actions. ScriptUpdate notifies consumers that the locations changed."},{"label":"Trust review","description":"Show script source, publisher, and version before execution. Users must understand who authored the actions."},{"label":"User consent","description":"Each script-driven action needs explicit approval with plain-language preview, same as any transaction."},{"label":"Execution","description":"The script builds the contract call your UI submits. Failed or unverified scripts should disable actions, not fail silently."}],"statesToDesign":[{"state":"Script verified","trigger":"The client supports the selected script format and its source and integrity checks pass.","userNeed":"Understand the action the script will build.","designResponse":"Show the script source, capabilities, contract call, and explicit consent control."},{"state":"Awaiting signature","trigger":"The verified script built a contract call and the wallet prompt is open.","userNeed":"Know what the token action will authorize.","designResponse":"Mirror the action summary in the app and wallet when supported; keep an app preview when wallet rendering differs."},{"state":"Pending","trigger":"The client submitted the contract call built from the script.","userNeed":"Know whether the action is progressing.","designResponse":"Show the transaction status and keep the script source and action context available."},{"state":"Succeeded","trigger":"The contract call is confirmed on chain.","userNeed":"See the resulting token or service state.","designResponse":"Show the contract result and script execution result separately when the client can distinguish them."},{"state":"Unverified or failed","trigger":"Source validation, script parsing, wallet signing, or contract execution fails.","userNeed":"Know whether to retry or use the built-in path.","designResponse":"Name the failed check, keep script actions disabled, and offer a supported fallback."}],"designDecisions":[{"question":"What do users review before a script action?","recommendation":"Lead with the action outcome and disclose source, capabilities, contract, and parameters behind the review step.","rationale":"A token-published script can build a contract call, so users need both the result and the authority boundary."},{"question":"What happens when script support is missing?","recommendation":"Disable script actions with an explanation and offer the built-in token flow.","rationale":"The interface does not require every client to implement a script format or runtime."},{"question":"How do you label script capability?","recommendation":"Show supported actions and isolation limits before consent.","rationale":"A script URI does not define the client's runtime or capability policy."}],"problemsSolved":[{"problem":"Token-specific actions need a discoverable source","oldWay":"Each client hardcodes token action metadata","newWay":"A compatible client can read scriptURI and choose a supported resource","impact":"high"},{"problem":"Users cannot assess token-linked actions before execution","oldWay":"A client runs or hides a script without source, integrity, or capability context","newWay":"The product can show source, verification, action summary, and explicit consent","impact":"high"},{"problem":"Unsupported formats and script failures are opaque","oldWay":"A generic action error leaves users unsure whether the script or contract failed","newWay":"Mapped verification, execution, rejection, and fallback states explain what to do next","impact":"medium"}],"uxPatterns":[{"name":"Dynamic Token Actions","description":"Discover actions from scriptURI.","components":["ActionList","ScriptBadge"],"userFlow":["User views a token in a supporting client","Client reads the scriptURI array and selects a supported resource","Client validates source authenticity and integrity under its trust policy","Expose supported actions only after verification"]},{"name":"Script Consent Modal","description":"Explicit approval before a verified script builds or submits a contract action.","components":["ConsentModal","SourceIndicator"],"userFlow":["Action selected","Script source shown","User approves","Client applies its configured isolation and capability policy before execution"]}],"antiPatterns":[{"pattern":"Presenting a token script as trusted by default","why":"ERC-5169 publishes locations but does not mandate format support, integrity, sandboxing, or safety","instead":"Show source, integrity, capability policy, and an explicit consent step before exposing actions","severity":"critical"},{"pattern":"Hiding script capability or isolation limits","why":"Users cannot understand what a client-side script may do","instead":"Use outcome language with capability and isolation disclosure available","severity":"high"},{"pattern":"No fallback when the client lacks script support","why":"Users lose access to the base token flow or cannot recover from verification failure","instead":"Explain the limitation and offer a built-in action or other supported path","severity":"high"}],"vocabulary":[{"use":"Token action","avoid":"Official script","why":"A token-published URI is not proof that the source or action is safe."},{"use":"Action unavailable","avoid":"Script failed","why":"Name whether verification, client support, user consent, or the contract action failed."},{"use":"Review and confirm","avoid":"Run script","why":"Users are approving a specific contract action, not blindly executing a URI."}],"specConstraints":[{"id":"script-update-notification","constraint":"ScriptUpdate must be emitted when setScriptURI updates the script URI so compatible wallets can refresh cached scripts.","appliesTo":"wallet","normativity":"normative","specQuote":"- The `ScriptUpdate(...)` event MUST be emitted when the ```setScriptURI``` function updates the `scriptURI`.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#specification","designImplication":"Invalidate cached script actions on update and show the new source/integrity state before exposing actions again."},{"id":"script-update-authority","constraint":"setScriptURI must verify the owner before changing script state.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- The `setScriptURI(...)` function MUST validate that `owner == msg.sender` *before* executing its logic and updating any state.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#specification","designImplication":"Show the authority that can change script-driven actions and require a fresh trust review after an update."},{"id":"script-update-state","constraint":"setScriptURI updates the current script URI state.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- The `setScriptURI(...)` function MUST update its internal state such that `currentScriptURI = newScriptURI`.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#specification","designImplication":"Treat a script update as a visible version change and keep the previous script state from silently remaining active."},{"id":"script-uri-discovery","constraint":"scriptURI returns the current script URI state used to locate the client script.","appliesTo":"application","normativity":"normative","specQuote":"- The `scriptURI()` function MUST return the `currentScriptURI` state.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#specification","designImplication":"Show the source URI and its supported client/format status before offering script-built actions."},{"id":"script-authenticity","constraint":"Clients must validate script immutability, URI hash integrity, or the separate authenticity-signature mechanism before using a script.","appliesTo":"application","normativity":"normative","specQuote":"- Any user of the script learned from `scriptURI` MUST validate the script is either at an immutable location, its URI contains its hash digest, or it implements the separate `Authenticity for Client Script` EIP, which asserts authenticity using signatures instead of a digest.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#specification","designImplication":"Keep script actions hidden or read-only until integrity/authenticity passes, and show the validation method and failure state."},{"id":"token-standard-compat","constraint":"The script URI standard is backwards-compatible with common token standards including ERC-20, ERC-721, ERC-777, and ERC-1155.","appliesTo":"application","normativity":"backwards-compatibility","specQuote":"## Backwards Compatibility\n\nThis standard is backwards-compatible with most existing token standards, including the following commonly-used ones:\n\n- [ERC-20](./eip-20.md)\n- [ERC-721](./eip-721.md)\n- [ERC-777](./eip-777.md)\n- [ERC-1155](./eip-1155.md)","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#backwards-compatibility","designImplication":"Use the token’s existing identity and ownership UI while making script support an explicit capability rather than an assumed wallet feature."},{"id":"script-server-trust","constraint":"When scripts call server APIs, the EIP does not authenticate the API endpoint; client-script trust does not make the server trustworthy.","appliesTo":"application","normativity":"security-considerations","specQuote":"## Security Considerations\n\n**When a server is involved**\n\nWhen the client script does not purely rely on connection to a blockchain node, but also calls server APIs,  the trustworthiness of the server API is called into question. This EIP does not provide any mechanism to assert the authenticity of the API access point. Instead, as long as the client script is trusted, it's assumed that it can call any server API in order to carry out token functions. This means the client script can mistrust a server API access point.\n\n**When the scriptURI doesn't contain integrity (hash) information**\n\nWe separately authored `Authenticity for Client Script` EIP to guide on how to use digital signatures efficiently and concisely to ensure authenticity and integrity of scripts not stored at a URI which is a digest of the script itself.","specSection":"Security Considerations","specUrl":"https://ercs.ethereum.org/ERCS/erc-5169#security-considerations","designImplication":"Show server/API trust boundaries and avoid presenting a verified script as proof that every offchain endpoint it calls is safe."}],"technicalNotes":"ERC-5169 defines scriptURI() returning string[], an owner-controlled setScriptURI and the ScriptUpdate event. Consumers must validate an immutable location, a content hash in the URI, or the referenced authenticity mechanism. The ERC mandates neither TokenScript nor a sandbox/runtime. Clients must supply format support, execution isolation, capability limits and explicit user consent; failed verification disables actions.","relatedStandards":[{"id":"ERC-1046","relationship":"Token logo and metadata complement"},{"id":"EIP-747","relationship":"Token icon and metadata standards"}]},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-5169","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-5169","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-5169","markdown":"https://www.eipsfordesigners.com/standards/ERC-5169/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-5169/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-5169","official":"https://ercs.ethereum.org/ERCS/erc-5169","discussion":"https://ethereum-magicians.org/search?q=ERC-5169"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}