EIP-1155|Standards Track: ERC|狀態 Final|建立 2018-06-17|Requires: EIP-165
作者:Witek Radomski、Andrew Cooke、Philippe Castonguay、James Therien、Eric Binet、Ronan Sandford|授權 CC0
規格原文:https://eips.ethereum.org/EIPS/eip-1155
介面 ID:ERC1155 = 0xd9b67a26ERC1155TokenReceiver = 0x4e2312e0ERC1155Metadata_URI = 0x0e89341c

🎯 什麼情境該想到我

當你「一個專案要發很多種代幣,不想每種都部署一個合約」或「要一筆交易轉多種代幣」的時候。

⚙️ 怎麼用(步驟 / 公式)

核心概念:_id 就是「代幣型別」

一個合約管任意多種型別,每個 _id 可以是同質化、非同質化、或半同質化,各自有自己的 metadata、供給量與屬性。
動機很直白:ERC-20/721 每一種代幣或每一個收藏都要部署一個合約,鏈上塞滿重複 bytecode——遊戲開發者可能要幾千種道具。

介面(全部 MUST 實作)

函式語義
safeTransferFrom(_from, _to, _id, _value, _data)轉單一型別
safeBatchTransferFrom(_from, _to, _ids[], _values[], _data)一次轉多種型別_ids_values 長度不符 MUST revert
balanceOf(_owner, _id)查某人某型別的餘額
balanceOfBatch(_owners[], _ids[])一次查多組 (owner, id)
setApprovalForAll(_operator, _approved)授權 operator 管理你全部的代幣
isApprovedForAll(_owner, _operator)查詢授權狀態

共同的 MUST revert 條件:_to 是零地址、餘額不足、任何其他錯誤。

⭐ 只有安全轉移,沒有不安全版本

規格的 “Design decision: Safe transfers only” 明講理由:讓接收方合約可以依賴「轉帳結尾一定會呼叫 hook」
接收方 MUST 實作 ERC1155TokenReceiver 全部函式,回傳 magic value:

  • onERC1155Received0xf23a6e61
  • onERC1155BatchReceived0xbc197c81

回傳其他值或 throw,轉帳 MUST 被 revert。且 hook 呼叫前,餘額必須已更新、事件必須已發出
EOA 收款不得呼叫 hook。

⭐ 事件足以重建全部餘額(Guaranteed log trace)

這是本規格最值得注意的硬性保證:光靠 TransferSingleTransferBatch 事件,就能算出所有當前餘額。因此——

  • 鑄造 _from MUST 設 0x0;銷毀 _to MUST 設 0x0
  • 連合約建構期給定的初始餘額也 MUST 發事件。
  • 甚至「重新部署到新合約地址」也 MUST 從新地址發事件來複製舊狀態(規格建議改用 proxy 模式,點名 EIP-2535)。
  • 客戶端可以用「從 0x0 轉出總量 − 轉入 0x0 總量」算流通量。
  • 想廣播「這個 ID 存在但還沒有餘額」,SHOULD 發一個 0x0 → 0x0_value 為 0 的 TransferSingle

metadata:{id} 字串替換

選配擴充 ERC1155Metadata_URI 提供 uri(uint256 _id)。URI 裡的 {id} 由客戶端替換:

  • 小寫十六進位 [0-9a-f]、無 0x 前綴、前補零到 64 字元
  • 範例:https://token-cdn-domain/{id}.json 在查 token ID 3145920x4CCE0)時變成
    https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json

URI 變更(若非動態產生)MUST 發 URI 事件;uri() MUST 回傳與最新事件相同的值。
uri() MUST NOT 用來判斷 token 是否存在——不存在的 ID 也可能回傳一個合法字串。

刻意沒有 namesymbol

規格說明理由:symbol 容易碰撞、對通用虛擬物品沒有全域價值;name 移到 JSON metadata,讓 metadata 成為資產名稱的唯一定義來源,並且支援在地化(規格附了 es.jsonfr.json 的範例)——名稱若上鏈,每種語言都存一份會貴到不可行。

混合實作(ERC-1155/ERC-721 雙標準)

順序 MUST 是:先對接收方呼叫 supportsInterface(0x4e2312e0)提供至少 10,000 gas
true → 走 1155 的 hook 流程;失敗或非 true → 可依另一個標準的規則處理。
但無論走哪條,1155 的轉帳事件仍 MUST 發出(否則餘額就無法只靠事件推導)。
規格建議:盡量純實作單一標準,不要做混合。

🧪 我實際套用的紀錄

  • 2026-08-27:(待填)

⚠️ 注意 / 什麼時候不適用

1. 授權是全有全無

setApprovalForAll 一授權就是你全部的代幣型別。規格明說要限制到特定 ID/數量,得另外用介面或外部合約(點名 ERC-1761 Scoped Approval)。
擁有者 SHOULD 被視為永遠能操作自己的代幣,不需要先把自己設成 operator。

2. 三個標準的取捨(我的整理)

ERC-20ERC-721ERC-1155
一個合約裝幾種1 種1 個收藏(多顆唯一)任意多種型別
批次轉帳
不安全轉移只有不安全兩種都有只有安全
事件可重建餘額未保證建構期有例外硬性保證
namesymbol選配在 metadata 擴充刻意移除

3. 半同質化與「數量為 1 的非同質化」

規格提到一種簡單做法:讓非同質化的型別最大值為 1,直接對應現實世界「獨特物品數量是 1、可替代物品數量大於 1」。

4. 非標準轉帳 API 也要守事件規則

即使你用自己的轉帳函式(非 safeTransferFrom),餘額與事件規則完全相同;差別只在非標準函式 MAY 在接收方沒實作 hook 時仍繼續轉帳,而標準的 safe 函式 MUST revert。

5. hook 的重入面向

餘額更新與事件都在 hook 呼叫之前完成,這是規格刻意的排序;但接收方 hook 內可以再發起轉帳(規格的 Scenario#8 明白允許轉發)。合約設計要照 工具-智能合約安全反模式 的清單檢查。

🔗 相關工具