{"id":"ERC-1155","name":"Multi Token Standard","status":"Final","chain":"both","category":{"id":"nft","name":"NFT Capabilities","description":"What NFTs can do beyond basic ownership"},"journeyStages":[{"id":"asset-display","name":"Asset Discovery & Display","description":"Seeing tokens, NFTs, and balances"},{"id":"executing","name":"Executing Transactions","description":"Performing on-chain actions"}],"uxImpact":"ERC-1155 defines balances by account and token ID, allowing one contract to represent fungible quantities and unique items. Its batch transfer moves multiple IDs and amounts to one recipient in a transaction. Clients still need receiver handling, metadata and indexing support; actual fees depend on the transaction and network.","officialUrl":"https://ercs.ethereum.org/ERCS/erc-1155","lastReviewed":"2026-09-18","lastUpdated":"2026-09-18","kind":"proposal","hasDetailedContent":true,"content":{"id":"ERC-1155","summary":"ERC-1155 defines balances by account and token ID, allowing one contract to represent fungible quantities and unique items. Its batch transfer moves multiple IDs and amounts to one recipient in a transaction. Clients still need receiver handling, metadata and indexing support; actual fees depend on the transaction and network.","applicability":{"whenToUse":["One contract holds many item types with different balances per id.","Games or marketplaces need batch send in one step; burn and trade behavior comes from extensions or application logic.","You mix fungible stacks and unique items without separate ERC-20/721 contracts."],"whenToAvoid":["Every asset is a single unique NFT (ERC-721 is simpler).","Users only swap fungible tokens with no per-id inventory.","Wallets cannot render quantity balances per id clearly."]},"designerTakeaways":["Show quantities per token ID; label an item unique only when verified supply and minting policy support that claim.","You can batch-transfer multiple IDs in one confirmation; show the current fee estimate and transaction count instead of promising savings.","Group fungible stacks and distinct items using verified collection metadata, with a fallback for missing information."],"problemsSolved":[{"problem":"Separate contracts for each item type","oldWay":"Deploy contract for swords, another for shields, another for potions...","newWay":"One contract holds all items with different IDs","impact":"critical"},{"problem":"Sending several item types can require repeated confirmations","oldWay":"A UI may require one transfer confirmation per item; transaction count and fees depend on the implementation and network","newWay":"safeBatchTransferFrom sends multiple IDs and quantities to one recipient in a transaction; check the client, recipient, and current fee estimate.","impact":"high"},{"problem":"Different item quantities need a common interface","oldWay":"Separate token contracts or custom interfaces make mixed inventories harder to integrate","newWay":"One contract exposes balances per ID; the collection defines supply, minting, and any uniqueness policy.","impact":"high"}],"uxPatterns":[{"name":"Game Inventory","description":"Display mixed item types in one view","userFlow":["User opens inventory","App uses a verified collection or indexer source to enumerate relevant token IDs and queries balances","Groups by category/type","Shows quantity for each ID","Marks unique items specially only when supply metadata is verified"]},{"name":"Batch Transfer","description":"Send multiple items in one transaction","userFlow":["User selects multiple items","Adjusts quantities for each","App shows batch preview","Shows the current fee estimate and transaction count without promising savings","Single transaction sends all"]},{"name":"Collection Overview","description":"Show collection with supply info","userFlow":["User views collection page","App lists token IDs from a verified collection or indexer source, or labels enumeration as unavailable","Shows current quantity or total supply per ID only when a verified extension or indexer provides it","Shows user balance per ID","Separates any advertised max supply from current quantity and labels rarity only when its source is verified"]}],"uiComponents":[{"name":"ItemCard","description":"Single item with quantity badge","states":["owned","not-owned","selected","transferring"],"props":["tokenId","metadata","balance","onSelect"]},{"name":"QuantitySelector","description":"Adjust quantity for transfer/use","states":["idle","editing","max-reached"],"props":["value","max","onChange"]},{"name":"BatchTransferForm","description":"Select multiple items + quantities","states":["selecting","ready","sending","complete"],"props":["items[]","recipient","onTransfer"]},{"name":"SupplyBadge","description":"Show current supply and any separate maximum only from a verified extension, indexer, or collection policy; otherwise show unknown.","states":["loading","known","unknown","error"],"props":["currentSupply","maxSupply","source","observedAt"]}],"antiPatterns":[{"pattern":"Not showing quantities clearly","why":"User doesn't know they have 50 of something","instead":"Always show \"x50\" or quantity badge","severity":"high"},{"pattern":"Treating all 1155 tokens as unique","why":"Fungible items (potions) don't need individual cards","instead":"Stack same IDs, show quantity","severity":"medium"},{"pattern":"Only offering single-item transfers","why":"Repeated confirmations make multi-item workflows cumbersome; fee differences require current estimates.","instead":"Offer batch transfer where the client and recipient support the flow, show a current estimate, and retain a single-item fallback.","severity":"high"},{"pattern":"Presenting unverified supply or rarity as fact","why":"ERC-1155 has no required total-supply or maximum-supply query, and a current supply of one does not prove that more cannot be minted.","instead":"Show verified current supply, maximum-supply policy, and data source separately; label unavailable information unknown.","severity":"medium"}],"specConstraints":[{"id":"circulating-supply-derivation","constraint":"Clients MAY derive circulating supply for a token ID from TransferSingle and TransferBatch values moving from and to the zero address.","appliesTo":"application","normativity":"normative","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"If a product shows circulating supply, label it as a derived event-based value with its token ID and observation source; do not present it as a required contract field.","specQuote":"* The total value transferred from address `0x0` minus the total value transferred to `0x0` observed via the `TransferSingle` and `TransferBatch` events MAY be used by clients and exchanges to determine the \"circulating supply\" for a given token ID."},{"id":"token-existence-broadcast","constraint":"A contract SHOULD emit a zero-to-zero TransferSingle event to broadcast a token ID that has no initial balance.","appliesTo":"account-implementation","normativity":"normative","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Let indexers surface a known token ID even when its initial balance is zero, while keeping the event as a discovery record rather than inventing ownership.","specQuote":"* To broadcast the existence of a token ID with no initial balance, the contract SHOULD emit the `TransferSingle` event from `0x0` to `0x0`, with the token creator as `_operator`, and a `_value` of 0."},{"id":"metadata-decimal-display","constraint":"Metadata describes how many decimal places token amounts should display.","appliesTo":"application","normativity":"normative","specSection":"Specification > Metadata > ERC-1155 Metadata URI JSON Schema","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Use the metadata decimal hint to format quantities while keeping raw values and an unavailable/unknown state when the field is absent or invalid.","specQuote":"\"description\": \"The number of decimal places that the token amount should display - e.g. 18, means to divide the token amount by 1000000000000000000 to get its user representation.\""},{"id":"scoped-approval-extension","constraint":"Implementations MAY add approval scopes for token IDs, quantities, or other rules through another interface or external contract.","appliesTo":"application","normativity":"rationale","specSection":"Rationale > Approval","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Distinguish collection-wide operator approval from any scoped permission path, name the scope before signing, and feature-detect the extension instead of assuming it exists.","specQuote":"Restricting approval to a certain set of token IDs, quantities or other rules MAY be done with an additional interface or an external contract. The rationale is to keep the ERC-1155 standard as generic as possible for all use-cases without imposing a specific approval scheme on implementations that may not need it. Standard token approval interfaces can be used, such as the suggested [ERC-1761 Scoped Approval Interface](./eip-1761.md) which is compatible with ERC-1155."},{"id":"erc1155-interface-support","constraint":"An ERC-1155 contract MUST implement every function in the ERC1155 interface and report support for its ERC-165 interface ID.","appliesTo":"account-implementation","normativity":"normative","specQuote":"**Smart contracts implementing the ERC-1155 standard MUST implement all of the functions in the `ERC1155` interface.**\n\n**Smart contracts implementing the ERC-1155 standard MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if `0xd9b67a26` is passed through the `interfaceID` argument.**","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Feature-detect the core interface before presenting ERC-1155 ownership, balance, transfer, or approval actions; do not infer support from collection metadata alone."},{"id":"transfer-event-emission","constraint":"A transfer, including a zero-value transfer, mint, or burn, MUST emit TransferSingle or TransferBatch.","appliesTo":"account-implementation","normativity":"normative","specQuote":"@dev Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see \"Safe Transfer Rules\" section of the standard).","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Build activity, balance, and supply views from the standard transfer events and keep zero-value, mint, and burn records visible when they explain state changes."},{"id":"transfer-event-balance-conservation","constraint":"The value in a transfer event MUST match the holder balance decrease and recipient balance increase.","appliesTo":"account-implementation","normativity":"normative","specQuote":"The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Treat event-derived balances as an accounting record: show quantities and activity that agree, and flag an indexer or receipt when those records cannot be reconciled."},{"id":"transfer-event-identity","constraint":"A transfer event MUST identify the holder whose balance decreases, the recipient whose balance increases, and the token type being transferred.","appliesTo":"account-implementation","normativity":"normative","specQuote":"The `_from` argument MUST be the address of the holder whose balance is decreased.\n        The `_to` argument MUST be the address of the recipient whose balance is increased.\n        The `_id` argument MUST be the token type being transferred.","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep sender, recipient, and token ID distinct in activity and receipt views; never collapse a multi-token event into an unqualified transfer label."},{"id":"transfer-operator-approval","constraint":"A transfer caller must be approved to manage the tokens being transferred.","appliesTo":"application","normativity":"normative","specQuote":"@dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see \"Approval\" section of the standard).","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Show the operator and approval scope before a transfer is signed; do not make a user infer that an approval or operator permission exists from the transfer button alone."},{"id":"approval-for-all-scope","constraint":"setApprovalForAll gives an operator authority over the approver's entire token set.","appliesTo":"application","normativity":"normative","specQuote":"The function `setApprovalForAll` allows an operator to manage one's entire set of tokens on behalf of the approver.","specSection":"Specification > Approval","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Describe this as collection-wide permission, name the operator, and provide a clear revoke path; do not present it as approval for only the item currently on screen."},{"id":"approval-event-emission","constraint":"Changing an operator's approval state MUST emit ApprovalForAll; absence of the event means disabled.","appliesTo":"account-implementation","normativity":"normative","specQuote":"@dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled).","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Use the ApprovalForAll event as a permission-history signal and show an unavailable or disabled state when the event is absent rather than assuming approval."},{"id":"owner-self-approval","constraint":"An owner SHOULD NOT have to call setApprovalForAll to operate on their own tokens.","appliesTo":"application","normativity":"normative","specQuote":"An owner SHOULD be assumed to always be able to operate on their own tokens regardless of approval status, so should SHOULD NOT have to call `setApprovalForAll` to approve themselves as an operator before they can operate on them.","specSection":"Specification > Approval","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Do not insert a self-approval transaction into a normal owner transfer flow; reserve operator approval for a distinct third-party permission decision."},{"id":"single-transfer-preconditions","constraint":"safeTransferFrom MUST revert for a zero recipient, an insufficient balance, or any other error.","appliesTo":"application","normativity":"normative","specQuote":"MUST revert if `_to` is the zero address.\n        MUST revert if balance of holder for token `_id` is lower than the `_value` sent.\n        MUST revert on any other error.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Validate recipient and available quantity before signing, then keep explicit rejected, insufficient-balance, and unknown-error states instead of showing a transfer as pending indefinitely."},{"id":"batch-transfer-shape","constraint":"safeBatchTransferFrom MUST reject a zero recipient, mismatched ID/value arrays, insufficient balances, and other errors.","appliesTo":"application","normativity":"normative","specQuote":"MUST revert if `_to` is the zero address.\n        MUST revert if length of `_ids` is not the same as length of `_values`.\n        MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient.\n        MUST revert on any other error.        ","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep every selected token ID paired with exactly one quantity, validate each balance in the preview, and identify the item that blocks a batch."},{"id":"batch-transfer-order","constraint":"Batch balance changes and events MUST follow the submitted ID/value array order.","appliesTo":"account-implementation","normativity":"normative","specQuote":"Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc).","specSection":"Specification","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Preserve the order shown in the confirmation and receipt views, or clearly show any intentional client-side sorting before the user signs."},{"id":"single-receiver-hook","constraint":"safeTransferFrom MUST check contract recipients and call onERC1155Received when the recipient is a smart contract.","appliesTo":"account-implementation","normativity":"normative","specQuote":"* After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see \"onERC1155Received rules\" section).","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Make recipient-contract compatibility part of the transfer path and explain why a contract recipient can reject a transfer after the user has reviewed the amount."},{"id":"batch-receiver-hook","constraint":"safeBatchTransferFrom MUST check contract recipients and call the applicable receiver hook.","appliesTo":"account-implementation","normativity":"normative","specQuote":"* After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` or `onERC1155BatchReceived` on `_to` and act appropriately (see \"onERC1155Received and onERC1155BatchReceived rules\" section).","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep a batch transfer's recipient capability check visible in the preview and provide a single-item fallback only when the actual recipient supports it."},{"id":"receiver-interface-functions","constraint":"A receiving smart contract MUST implement every ERC1155TokenReceiver function to accept transfers.","appliesTo":"account-implementation","normativity":"normative","specQuote":"**Smart contracts MUST implement all of the functions in the `ERC1155TokenReceiver` interface to accept transfers. See \"Safe Transfer Rules\" for further detail.**","specSection":"Specification > ERC-1155 Token Receiver","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Treat a contract recipient as unsupported until its receiver interface is detected; do not promise delivery based only on its address or collection name."},{"id":"receiver-interface-detection","constraint":"A receiving smart contract MUST signal ERC1155TokenReceiver support through ERC-165 to accept transfers.","appliesTo":"account-implementation","normativity":"normative","specQuote":"**Smart contracts MUST implement the ERC-165 `supportsInterface` function and signify support for the `ERC1155TokenReceiver` interface to accept transfers. See \"ERC1155TokenReceiver ERC-165 rules\" for further detail.**","specSection":"Specification > ERC-1155 Token Receiver","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Use the receiver capability result as a first-class recipient state and distinguish unsupported, detected, and failed capability checks."},{"id":"safe-transfer-rejection","constraint":"safeTransferFrom and safeBatchTransferFrom MUST revert when a receiving contract lacks the receiver interface; a non-standard function MAY proceed.","appliesTo":"application","normativity":"normative","specQuote":"- However while the `safeTransferFrom` or `safeBatchTransferFrom` functions MUST revert if a receiving contract does not implement the `ERC1155TokenReceiver` interface, a non-standard function MAY proceed with the transfer.","specSection":"Specification > Safe Transfer Rules > Scenarios","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Do not silently switch from a safe transfer to a custom transfer when the recipient is incompatible; make the alternative explicit and label its different recovery risk."},{"id":"receiver-hook-scope","constraint":"Receiver hooks MUST NOT be called on EOAs or outside a mint or transfer process.","appliesTo":"account-implementation","normativity":"normative","specQuote":"**_Scenario#1 :_** The recipient is not a contract.\n* `onERC1155Received` and `onERC1155BatchReceived` MUST NOT be called on an EOA (Externally Owned Account).\n\n**_Scenario#2 :_** The transaction is not a mint/transfer of a token.\n* `onERC1155Received` and `onERC1155BatchReceived` MUST NOT be called outside of a mint or transfer process.","specSection":"Specification > Safe Transfer Rules > Scenarios","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep ordinary EOA sends free of receiver-contract states, and only expose callback-dependent status during an actual mint or transfer."},{"id":"receiver-callback-rejection","constraint":"A receiver that throws or returns an unknown value MUST cause the transfer to revert.","appliesTo":"application","normativity":"normative","specQuote":"**_Scenario#4 :_** The receiver implements the necessary `ERC1155TokenReceiver` interface function(s) but returns an unknown value.\n* The transfer MUST be reverted.\n\n**_Scenario#5 :_** The receiver implements the necessary `ERC1155TokenReceiver` interface function(s) but throws an error.\n* The transfer MUST be reverted.","specSection":"Specification > Safe Transfer Rules > Scenarios","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep custody and balance unchanged in the UI until the callback is accepted, and explain that a receiver rejection is a failed transfer rather than a delayed confirmation."},{"id":"receiver-state-before-hook","constraint":"For a contract recipient, balances and the transfer event MUST be updated before the receiver hook, and a receiver hook MUST be called.","appliesTo":"account-implementation","normativity":"normative","specQuote":"* The balances for the transfer MUST have been updated before the `ERC1155TokenReceiver` hook is called on a recipient contract.\n* The transfer event MUST have been emitted to reflect the balance changes before the `ERC1155TokenReceiver` hook is called on the recipient contract.\n* One of `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient contract.","specSection":"Specification > Safe Transfer Rules > Scenarios","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Show receipt, activity, and receiver-processing states in an order consistent with the event and balance transition; do not present callback processing as preceding the transfer itself."},{"id":"batch-callback-coverage","constraint":"A batch receiver MUST receive enough hooks to account for every balance change, after balances and events are updated.","appliesTo":"account-implementation","normativity":"normative","specQuote":"* All balance transfers that are referenced in a call to an `ERC1155TokenReceiver` hook MUST be updated before the `ERC1155TokenReceiver` hook is called on the recipient contract.\n* All transfer events MUST have been emitted to reflect current balance changes before an `ERC1155TokenReceiver` hook is called on the recipient contract.\n* `onERC1155Received` or `onERC1155BatchReceived` MUST be called on the recipient as many times as necessary such that every balance change for the recipient in the scenario is accounted for.","specSection":"Specification > Safe Transfer Rules > Scenarios","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Let batch receipts account for every selected ID and quantity, and reconcile the final activity view against all callbacks rather than assuming one callback means one item."},{"id":"single-receiver-acceptance","constraint":"onERC1155Received MUST return the prescribed magic value to accept a transfer; rejection or any other return value MUST revert it.","appliesTo":"account-implementation","normativity":"normative","specQuote":"This function MUST return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` (i.e. 0xf23a6e61) if it accepts the transfer.\n        This function MUST revert if it rejects the transfer.\n        Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.","specSection":"Specification > ERC-1155 Token Receiver","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Use an explicit receiver-accepted versus receiver-rejected result and never mark the transfer complete on an unrecognized callback value."},{"id":"batch-receiver-acceptance","constraint":"onERC1155BatchReceived MUST return the prescribed magic value to accept a batch; rejection or any other return value MUST revert it.","appliesTo":"account-implementation","normativity":"normative","specQuote":"This function MUST return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` (i.e. 0xbc197c81) if it accepts the transfer(s).\n        This function MUST revert if it rejects the transfer(s).\n        Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.","specSection":"Specification > ERC-1155 Token Receiver","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep batch acceptance as one atomic status in the UI and show the whole batch as failed when the receiver rejects the callback."},{"id":"receiver-gas-budget","constraint":"The receiver's ERC-165 support check MUST NOT consume more than 10,000 gas.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- It MUST NOT consume more than 10,000 gas.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Treat a receiver capability check as a bounded probe and give the user a clear unsupported or failed-recipient state when the check cannot complete."},{"id":"event-derived-balance","constraint":"A viewer MUST be able to query a balance through the standard function and get the same balance as the transfer events imply.","appliesTo":"application","normativity":"normative","specQuote":"- i.e. an external viewer MUST still be able to query the balance via a standard function and it MUST be identical to the balance as determined by `TransferSingle` and `TransferBatch` events alone.","specSection":"Specification > Safe Transfer Rules > Scenarios","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Reconcile indexed balances with on-chain balance queries and show an indexing or data freshness warning when the two disagree."},{"id":"nonstandard-transfer-compatibility","constraint":"An implementation-specific transfer MUST follow safe receiver rules when the receiver supports them; if not, the custom implementation SHOULD revert but MAY proceed.","appliesTo":"account-implementation","normativity":"normative","specQuote":"* If an implementation specific API function is used to transfer ERC-1155 token(s) to a contract, the `safeTransferFrom` or `safeBatchTransferFrom` (as appropriate) rules MUST still be followed if the receiver implements the `ERC1155TokenReceiver` interface. If it does not the non-standard implementation SHOULD revert but MAY proceed.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Label custom transfer paths separately from safe transfers and disclose the possibility of unrecoverable tokens when the recipient is not a receiver contract."},{"id":"mint-event-identity","constraint":"Mint events MUST use the zero address as `_from` to identify creation to contract observers.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- The \"TransferSingle and TransferBatch event rules\" MUST be followed as appropriate for the mint(s) (i.e. singles or batches) however the `_from` argument MUST be set to `0x0` (i.e. zero address) to flag the transfer as a mint to contract observers.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Label zero-address sources as mint activity in history and supply views; do not treat a mint as an ordinary user-to-user transfer."},{"id":"initial-balance-events","constraint":"Initial contract balances MUST be represented by events so the balance can be determined from events alone.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- __NOTE:__ This includes tokens that are given an initial balance in the contract. The balance of the contract MUST also be able to be determined by events alone meaning initial contract balances (for eg. in construction) MUST emit events to reflect those balances too.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Do not hide initial allocations from activity or supply indexing; include deployment-time event history when presenting a complete collection record."},{"id":"burn-event-identity","constraint":"Burn events MUST use the zero address as `_to` to identify destruction to contract observers.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- The \"TransferSingle and TransferBatch event rules\" MUST be followed as appropriate for the burn(s) (i.e. singles or batches) however the `_to` argument MUST be set to `0x0` (i.e. zero address) to flag the transfer as a burn to contract observers.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Label zero-address destinations as burn activity and keep burned quantities out of current balance totals without implying that a token was literally sent to an address."},{"id":"mint-burn-event-rules","constraint":"Mint and burn event rules MUST still be followed for non-safe APIs and hybrid standards.","appliesTo":"account-implementation","normativity":"normative","specQuote":"- Even in a non-safe API and/or hybrid standards case the above event rules MUST still be adhered to when minting/creating or burning/destroying.","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep mint and burn labels consistent across safe, custom, and hybrid transaction paths so activity history does not change meaning with the entry point."},{"id":"self-mint-hook-exception","constraint":"A contract MAY skip the receiver hook when minting to itself; other mint paths MUST follow receiver rules.","appliesTo":"account-implementation","normativity":"normative","specQuote":"* A contract MAY skip calling the `ERC1155TokenReceiver` hook function(s) if the mint operation is transferring the token(s) to itself. In all other cases the `ERC1155TokenReceiver` rules MUST be followed as appropriate for the implementation (i.e. safe, custom and/or hybrid).","specSection":"Specification > Safe Transfer Rules > Rules","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Allow a self-mint receipt to omit a receiver-callback state, but do not generalize that exception to external recipients."},{"id":"metadata-id-substitution","constraint":"Clients MUST replace `{id}` with a lowercase, zero-padded hexadecimal token ID when the URI uses ID substitution.","appliesTo":"application","normativity":"normative","specQuote":"The URI value allows for ID substitution by clients. If the string `{id}` exists in any URI, clients MUST replace this with the actual token ID in hexadecimal form. This allows for a large number of tokens to use the same on-chain string by defining a URI once, for that large number of tokens.\n\n* The string format of the substituted hexadecimal ID MUST be lowercase alphanumeric: `[0-9a-f]` with no 0x prefix.\n* The string format of the substituted hexadecimal ID MUST be leading zero padded to 64 hex characters length if necessary.","specSection":"Specification > Metadata","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Expand metadata URLs deterministically, preserve the 64-character lowercase format, and show a metadata-unavailable state when the resolved resource cannot be loaded."},{"id":"metadata-uri-schema","constraint":"An ERC-1155 metadata URI MUST point to JSON conforming to the ERC-1155 Metadata URI JSON Schema.","appliesTo":"application","normativity":"normative","specQuote":"The URI MUST point to a JSON file that conforms to the \"ERC-1155 Metadata URI JSON Schema\".","specSection":"Specification > Metadata","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Validate metadata before using it to label assets, and keep a structured fallback for missing, invalid, or incomplete fields."},{"id":"metadata-uri-event-sync","constraint":"When the metadata URI extension is used, expressible URI changes MUST emit URI, and `uri` MUST match the latest emitted value; clients SHOULD use `uri` when no event was emitted.","appliesTo":"account-implementation","normativity":"normative","specQuote":"If the optional `ERC1155Metadata_URI` extension is included:\n* The ERC-165 `supportsInterface` function MUST return the constant value `true` if `0x0e89341c` is passed through the `interfaceID` argument.\n* _Changes_ to the URI MUST emit the `URI` event if the change can be expressed with an event (i.e. it isn't dynamic/programmatic).\n    - An implementation MAY emit the `URI` event during a mint operation but it is NOT mandatory. An observer MAY fetch the metadata uri at mint time from the `uri` function if it was not emitted.    \n* The `uri` function SHOULD be used to retrieve values if no event was emitted. \n* The `uri` function MUST return the same value as the latest event for an `_id` if it was emitted.","specSection":"Specification > Metadata > Metadata Extensions","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Treat metadata events and `uri` reads as one freshness model, and show when a value is dynamic, event-backed, or fetched as a fallback."},{"id":"metadata-uri-not-existence","constraint":"The `uri` function MUST NOT be used to determine whether a token exists.","appliesTo":"application","normativity":"normative","specQuote":"* The `uri` function MUST NOT be used to check for the existence of a token as it is possible for an implementation to return a valid string even if the token does not exist.","specSection":"Specification > Metadata > Metadata Extensions","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Use balances, transfer history, or a verified collection/indexer source for existence; do not show a token as minted solely because a URI resolves."},{"id":"metadata-localization-substitution","constraint":"If a localization URI contains `{locale}`, clients MUST replace it with the chosen locale; localization itself MAY provide localized values.","appliesTo":"application","normativity":"normative","specQuote":"Metadata localization should be standardized to increase presentation uniformity across all languages. As such, a simple overlay method is proposed to enable localization. If the metadata JSON file contains a `localization` attribute, its content MAY be used to provide localized values for fields that need it. The `localization` attribute should be a sub-object with three attributes: `uri`, `default` and `locales`. If the string `{locale}` exists in any URI, it MUST be replaced with the chosen locale by all client software.","specSection":"Specification > Metadata > ERC-1155 Metadata URI JSON Schema > Localization","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Offer localized metadata as an optional overlay, keep the default locale visible, and resolve locale placeholders consistently across clients."},{"id":"upgrade-event-replication","constraint":"A redeployed ERC-1155 implementation MUST emit events from the new address to replicate the deprecated contract's final state.","appliesTo":"account-implementation","normativity":"rationale","specQuote":"The requirement to emit `TransferSingle` or `TransferBatch` on balance change implies that a valid implementation of ERC-1155 redeploying to a new contract address MUST emit events from the new contract address to replicate the deprecated contract final state. It is valid to only emit a minimal number of events to reflect only the final balance and omit all the transactions that led to that state. The event emit requirement is to ensure that the current state of the contract can always be traced only through events. To alleviate the need to emit events when changing contract address, consider using the proxy pattern, such as described in [EIP-2535](./eip-2535.md). This will also have the added benefit of providing a stable contract address for users.","specSection":"Rationale > Upgrades","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep collection links and indexed history stable across upgrades, and disclose when a migration uses a new contract address or a proxy."},{"id":"hybrid-receiver-compatibility","constraint":"A hybrid ERC-1155 implementation MUST check receiver support with supportsInterface before calling receiver hooks, providing at least 10,000 gas.","appliesTo":"account-implementation","normativity":"backwards-compatibility","specQuote":"Hence in a hybrid ERC-1155 contract implementation an extra call MUST be made on the recipient contract and checked before any hook calls to `onERC1155Received` or `onERC1155BatchReceived` are made.\nOrder of operation MUST therefore be:\n1. The implementation MUST call the function `supportsInterface(0x4e2312e0)` on the recipient contract, providing at least 10,000 gas.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Make hybrid-recipient detection a distinct compatibility state and do not promise the same receiver flow for every standard a contract may implement."},{"id":"hybrid-event-continuity","constraint":"ERC-1155 transfer events MUST still be emitted when a hybrid implementation uses another standard's transfer rules.","appliesTo":"account-implementation","normativity":"backwards-compatibility","specQuote":"An important consideration is that even if the tokens are sent with another standard's rules the *__ERC-1155 transfer events MUST still be emitted.__* This is so the balances can still be determined via events alone as per ERC-1155 standard rules.","specSection":"Backwards Compatibility","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Keep indexing and activity semantics anchored to ERC-1155 events even when the user-facing transfer path is shared with another token standard."},{"id":"event-derived-enumeration","constraint":"Token enumeration must use event logs, and clients such as exchanges and explorers are RECOMMENDED to maintain local token, supply, and URI data.","appliesTo":"application","normativity":"normative","specQuote":"In order to keep storage requirements light for contracts implementing ERC-1155, enumeration (discovering the IDs and values of tokens) must be done using event logs. It is RECOMMENDED that clients such as exchanges and blockchain explorers maintain a local database containing the token ID, Supply, and URI at the minimum. This can be built from each TransferSingle, TransferBatch, and URI event, starting from the block the smart contract was deployed until the latest block.","specSection":"Usage > Enumerating from events","specUrl":"https://ercs.ethereum.org/ERCS/erc-1155","designImplication":"Treat inventory enumeration as indexed data with an observed coverage range, not as a guaranteed contract query; show loading and incomplete-history states."}],"keyTakeaways":["One contract can expose multiple token IDs and quantities.","Show the holder’s balance for each ID.","Batch transfers can reduce confirmations; estimate fees for the actual transaction.","Enumeration, supply and rarity need a verified extension, indexer or collection source.","Stack identical IDs and distinguish current quantity from any minting cap."],"technicalNotes":"ERC-1155 defines balanceOf(account, id), balanceOfBatch, safeTransferFrom, safeBatchTransferFrom, and setApprovalForAll. A batch transfer targets one recipient; contract recipients must accept the applicable receiver callback. The optional metadata URI extension exposes uri(id) and supports {id} substitution. TransferSingle and TransferBatch events enable indexers to track IDs and balances, including mint/burn events, but the base interface has no token-ID enumeration, totalSupply, or maxSupply query. Verify any extension or indexer and its completeness before displaying supply. Burn and trade entry points are implementation-specific.","lastUpdated":"2026-09-18","sources":[{"label":"ERC-1155 official specification","url":"https://ercs.ethereum.org/ERCS/erc-1155","type":"official-spec"}],"lastReviewed":"2026-09-18"},"sources":[{"label":"Official specification","url":"https://ercs.ethereum.org/ERCS/erc-1155","type":"official-spec"},{"label":"Discussion search","url":"https://ethereum-magicians.org/search?q=ERC-1155","type":"discussion"}],"urls":{"canonical":"https://www.eipsfordesigners.com/standards/ERC-1155","markdown":"https://www.eipsfordesigners.com/standards/ERC-1155/content.md","agent":"https://www.eipsfordesigners.com/standards/ERC-1155/agent.md","api":"https://www.eipsfordesigners.com/api/standards/ERC-1155","official":"https://ercs.ethereum.org/ERCS/erc-1155","discussion":"https://ethereum-magicians.org/search?q=ERC-1155"},"freshness":{"lastReviewed":"2026-09-18","lastUpdated":"2026-09-18"}}