newsence
來源篩選

Draft ERC: Private ERC-1155 — Privacy-Preserving Multi-Token Standard

Ethereum Magicians

This proposal introduces a privacy-preserving extension to the ERC-1155 standard that uses Poseidon hash commitments and Groth16 ZK proofs to hide per-address balances and transfer amounts while maintaining public token types and total supplies.

newsence

草擬 ERC:隱私型 ERC-1155 — 具備隱私保護的多代幣標準

Ethereum Magicians
大約 4 小時前

AI 生成摘要

本提案為 ERC-1155 標準引入了隱私保護擴展,利用 Poseidon 哈希承諾與 Groth16 零知識證明來隱藏各地址的餘額與轉帳金額,同時保持代幣類型與總供應量的公開透明。

欄位

狀態
草案 (Draft)

類型
標準軌跡 (Standards Track)

類別
ERC

依賴項目
EIP-712, ERC-5564

摘要 (Abstract)

本 ERC 定義了一種具備隱私保護功能的 ERC-1155 多代幣標準。每個地址、每個 tokenId 的餘額透過 Poseidon 哈希承諾(hash commitments)進行隱藏,而其有效性則透過鏈上的 Groth16 零知識證明(ZK proofs)進行驗證。代幣類型(tokenId)和總供應量保持公開。

本標準將 模型擴展至多代幣場景——每個(地址, tokenId)對存儲一個隱藏餘額數量的承諾。所有權透過標準 ECDSA 簽名證明(兼容 MetaMask,無需自定義錢包)。

隱私模型:數量和各地址持有量被隱藏。代幣類型、轉帳圖譜(哪些 VOSA 進行了交易)以及每個 tokenId 的總供應量保持可見。這在保護餘額隱私的同時,也能滿足合規性要求。

核心特性

  • 每個 tokenId 的餘額隱私(數量隱藏在 Poseidon 承諾中)

  • 每個 tokenId 可進行任意數量的轉帳(非固定面額)

  • 鏈上 Groth16 ZK 證明驗證(完全去中心化)

  • 標準 ECDSA 簽名 + EVM 原生 20 字節地址

  • O(1) 支出追蹤,具備可配置的週期性清理功能

  • 跨多個 tokenId 的批量鑄造

  • 針對每個 tokenId 的策略(Policy,循環授權)和許可(Permit,一次性授權)

動機 (Motivation)

ERC-1155 的隱私缺口

ERC-1155 公開了所有持有資訊:

balanceOf(0x1234, tokenId=42) → 500 // 任何人都能看到各項目的持有量
TransferSingle(from, to, id, 100) // 數量是公開的

這在多代幣場景中會產生問題:

  • 遊戲:對手可以看到你的庫存(稀有道具、強化藥水、遊戲幣)

  • 忠誠度計畫:競爭對手可以看到積分餘額和兌換模式

  • 代幣化資產:投資組合構成完全透明

  • 收藏品:限量版項目的持有情況公開,可能導致針對性的社交工程攻擊

為何選擇 ERC-1155(多代幣)而非 ERC-721(單一 NFT)?

ERC-1155 涵蓋了更廣泛的使用場景。許多「NFT」應用實際上需要每種代幣類型具備同質化數量

使用場景
代幣模型
為何使用 1155?

遊戲道具
500 把劍,200 瓶藥水
每種類型內同質化,存在多種類型

活動門票
1000 張普通票,50 張 VIP 票
每個等級有對應數量

忠誠度積分
多個積分類別
每個類別內餘額同質化

代幣化商品
100 盎司黃金,50 盎司白銀
每個資產類型有對應數量

半同質化代幣
藝術品的第 1-100 號版本
相同類型,多個副本

對於真正獨一無二的 1-of-1 項目,只需將數量設為 1 —— 協議會將其視為特殊情況處理。

隱私對比

解決方案
數量隱私
持有者身份
轉帳圖譜
代幣類型可見
合規性

ERC-1155




透明

本標準


❌ (設計使然)

可審計

全隱私 NFT




困難

設計理念

本標準旨在實現餘額隱私,而非匿名混幣

  • ✅ 隱藏你持有每個項目的數量

  • ✅ 隱藏轉帳數量

  • ✅ 符合監管要求(資金流向可追溯,代幣類型可見)

  • ❌ 隱藏正在轉帳的代幣類型(tokenId 是公開的)

  • ❌ 完全匿名(轉帳圖譜是可見的)

規範 (Specification)

本文件中的關鍵詞「必須」(MUST)、「不得」(MUST NOT)、「要求」(REQUIRED)、「應當」(SHALL)、「不應當」(SHALL NOT)、「應該」(SHOULD)、「不應該」(SHOULD NOT)、「推薦」(RECOMMENDED)、「不推薦」(NOT RECOMMENDED)、「可以」(MAY) 和「可選」(OPTIONAL) 應按照 RFC 2119 和 RFC 8174 的描述進行解釋。

概述

┌──────────────────────────────────────────────────────────────────────────┐
│ 隱私 ERC-1155 架構 │
├──────────────────────────────────────────────────────────────────────────┤
│ │
│ 存儲: │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ mapping(address => mapping(uint256 => bytes32)) balanceCommitment │ │
│ │ mapping(uint256 => uint256) totalSupply │ │
│ │ mapping(address => mapping(uint256 => PolicyMeta)) policies │ │
│ │ mapping(address => mapping(uint256 => PermitMeta)) permits │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
│ 操作: │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ mint(recipient, tokenId, amount, commitment, proof) │ │
│ │ mintBatch(recipient, tokenIds[], amounts[], commitments[], ...) │ │
│ │ burn(input, tokenId, amount, proof, signature) │ │
│ │ transfer(tokenId, inputs[], outputs[], proof, signatures) │ │
│ │ consolidate(tokenId, inputs[], output, proof, signatures) │ │
│ │ createPolicy(tokenId, spender, commitment, proof, signature) │ │
│ │ createPermit(tokenId, spender, commitment, proof, signature) │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘

每個 (address, tokenId) 的鏈上狀態:

mapping(address => mapping(uint256 => bytes32)) balanceCommitment;
// bytes32(0) → 從未使用
// Poseidon(tokenId, amount, blinder, ts) → 活躍餘額(數量已隱藏)
// SPENT_PREFIX | block.number → 已支出(在週期窗口後可清理)

與隱私 ERC-20 的關鍵差異

維度
隱私 ERC-20
隱私 ERC-1155

存儲
address → commitment
address → tokenId → commitment

承諾 (Commitment)
Poseidon(amount, blinder, ts)
Poseidon(tokenId, amount, blinder, ts)

供應量
單一 totalSupply
每個代幣類型對應 totalSupply[tokenId]

策略/許可 (Policy/Permit)
按地址
按 (address, tokenId)

EIP-712
類型哈希中無 tokenId
所有類型哈希均包含 tokenId

批量鑄造
不適用
針對多個 tokenId 的 mintBatch()

轉帳
任意數量,單一代幣
每次轉帳調用僅限一個 tokenId

常量

bytes16 public constant SPENT_PREFIX = 0xDEADDEADDEADDEADDEADDEADDEADDEAD;
uint256 public constant MAX_INPUTS = 10;
uint256 public constant MAX_OUTPUTS = 10;
uint256 public constant TIMESTAMP_WINDOW = 2 hours;
uint256 public constant DEFAULT_CLEANUP_WINDOW = 216_000; // 約 1 個月

數據結構

struct PolicyMeta {
address owner;
address spender;
uint256 expiry; // 0 = 永不過期
bool revoked;
}

struct PermitMeta {
address owner;
address spender;
uint256 expiry;
bool revoked;
bool used; // 單次使用
}

struct CreatePolicyParams {
address input;
bytes32 inputCommitment;
address policyAddress;
bytes32 policyCommitment;
uint256 policyTimestamp;
address changeAddress;
bytes32 changeCommitment;
uint256 changeTimestamp;
address spender;
uint256 expiry;
uint256 deadline;
}

struct CreatePermitParams {
address input;
bytes32 inputCommitment;
address permitAddress;
bytes32 permitCommitment;
uint256 permitTimestamp;
address changeAddress;
bytes32 changeCommitment;
uint256 changeTimestamp;
address spender;
uint256 expiry;
uint256 deadline;
}

核心接口

元數據 (Metadata)

interface IPrivateERC1155Metadata {
function uri(uint256 tokenId) external view returns (string memory);
function totalSupply(uint256 tokenId) external view returns (uint256);
}

VOSA 狀態管理

interface IPrivateERC1155VOSA {
function balanceCommitment(address vosa, uint256 tokenId) external view returns (bytes32);
function hasBalance(address vosa, uint256 tokenId) external view returns (bool);
function isEverUsed(address vosa, uint256 tokenId) external view returns (bool);
function isSpent(address vosa, uint256 tokenId) external view returns (bool);
function batchHasBalance(address[] calldata addrs, uint256[] calldata tokenIds)
external view returns (bool[] memory);
}

核心操作

interface IPrivateERC1155Core {
/// @notice 鑄造代幣 — 發行時 tokenId 和數量是公開的
function mint(
address recipient, uint256 tokenId, uint256 amount, bytes32 commitment,
uint256 outputTimestamp, bytes calldata ephemeralPubKey,
bytes calldata proof, bytes calldata memo
) external returns (bool);

/// @notice 跨多個 tokenId 批量鑄造function mintBatch(    address recipient, uint256[] calldata tokenIds, uint256[] calldata amounts,    bytes32[] calldata commitments, uint256[] calldata outputTimestamps,    bytes[] calldata ephemeralPubKeys, bytes[] calldata proofs, bytes calldata memo) external returns (bool);/// @notice 銷毀代幣(全部或部分銷毀並找零)function burn(    address input, uint256 tokenId, bytes32 inputCommitment, uint256 amount,    address changeAddress, bytes32 changeCommitment, uint256 changeTimestamp,    bytes calldata changeEphemeralPubKey, bytes calldata signature,    bytes calldata proof, uint256 deadline) external returns (bool);/// @notice 隱私轉帳(N 個輸入 → M 個輸出,單一 tokenId,數量隱藏)function transfer(    uint256 tokenId, address[] calldata inputs, bytes32[] calldata inputCommitments,    address[] calldata outputs, bytes32[] calldata outputCommitments,    uint256[] calldata outputTimestamps, bytes[] calldata ephemeralPubKeys,    bytes[] calldata signatures, bytes calldata proof, uint256 deadline,    int256[] calldata policyChangeIndices, bytes calldata memo) external returns (bool);/// @notice 將相同 tokenId 的多個 VOSA 合併為一個function consolidate(    uint256 tokenId, address[] calldata inputs, bytes32[] calldata inputCommitments,    address output, bytes32 outputCommitment, uint256 outputTimestamp,    bytes calldata ephemeralPubKey, bytes[] calldata signatures,    bytes calldata proof, uint256 deadline) external returns (bool);

}

授權接口

策略(循環授權,按 tokenId)

interface IPrivateERC1155Policy {
function createPolicy(
uint256 tokenId, CreatePolicyParams calldata params,
bytes[] calldata ephemeralPubKeys, bytes calldata ownerSignature,
bytes calldata proof, bytes calldata memo
) external returns (bool);

function revokePolicy(address policyAddress, uint256 tokenId) external;function getPolicy(address policyAddress, uint256 tokenId) external view returns (    address owner, address spender, uint256 expiry, bool revoked, bool isActive);

}

許可(一次性授權,按 tokenId)

interface IPrivateERC1155Permit {
function createPermit(
uint256 tokenId, CreatePermitParams calldata params,
bytes[] calldata ephemeralPubKeys, bytes calldata ownerSignature,
bytes calldata proof, bytes calldata memo
) external returns (bool);

function revokePermit(address permitAddress, uint256 tokenId) external;function getPermit(address permitAddress, uint256 tokenId) external view returns (    address owner, address spender, uint256 expiry, bool revoked, bool used, bool isActive);

}

事件 (Events)

interface IPrivateERC1155Events {
event TransferSingle(address indexed operator, address[] inputs, address[] outputs,
uint256 indexed tokenId, bytes32[] outputCommitments,
bytes[] ephemeralPubKeys, bytes memo);
event TransferBatch(address indexed operator, address from, address to,
uint256[] tokenIds, bytes32[] outputCommitments,
bytes[] ephemeralPubKeys, bytes memo);
event Burn(address indexed input, uint256 indexed tokenId, uint256 amount,
address changeAddress, bytes32 changeCommitment, bytes changeEphemeralPubKey);
event Consolidate(uint256 indexed tokenId, address[] inputs, address indexed output,
bytes32 outputCommitment, bytes ephemeralPubKey);
event PolicyCreated(uint256 indexed tokenId, address indexed policyAddress,
address indexed owner, address spender, uint256 expiry,
bytes32 policyCommitment, address changeAddress, bytes32 changeCommitment,
bytes[] ephemeralPubKeys, bytes memo);
event PolicyRevoked(address indexed policyAddress, uint256 indexed tokenId);
event PolicyMigrated(address indexed oldAddress, address indexed newAddress,
uint256 indexed tokenId);
event PermitCreated(uint256 indexed tokenId, address indexed permitAddress,
address indexed owner, address spender, uint256 expiry,
bytes32 permitCommitment, address changeAddress, bytes32 changeCommitment,
bytes[] ephemeralPubKeys, bytes memo);
event PermitUsed(address indexed permitAddress, uint256 indexed tokenId);
event PermitRevoked(address indexed permitAddress, uint256 indexed tokenId);
event AddressCleaned(address indexed addr, uint256 indexed tokenId, uint256 spentBlock);
event MinterUpdated(address indexed newMinter);
event VerifierUpdated(string indexed verifierType, address indexed newVerifier);
event CleanupWindowUpdated(uint256 oldWindow, uint256 newWindow);
}

EIP-712 類型定義

所有類型哈希均將 tokenId 作為第一個欄位,將簽名綁定到特定的代幣類型:

bytes32 constant TRANSFER_1155_TYPEHASH = keccak256(
"Transfer1155(uint256 tokenId,bytes32 inputsHash,bytes32 inputCommitmentsHash,"
"bytes32 outputsHash,bytes32 outputCommitmentsHash,uint256 deadline)"
);

bytes32 constant BURN_1155_TYPEHASH = keccak256(
"Burn1155(uint256 tokenId,address input,bytes32 inputCommitment,uint256 amount,"
"address changeAddress,bytes32 changeCommitment,uint256 changeTimestamp,uint256 deadline)"
);

bytes32 constant CONSOLIDATE_1155_TYPEHASH = keccak256(
"Consolidate1155(uint256 tokenId,bytes32 inputsHash,bytes32 inputCommitmentsHash,"
"address output,bytes32 outputCommitment,uint256 deadline)"
);

bytes32 constant CREATE_POLICY_1155_TYPEHASH = keccak256(
"CreatePolicy1155(uint256 tokenId,address input,bytes32 inputCommitment,"
"address policyAddress,bytes32 policyCommitment,uint256 policyTimestamp,"
"address changeAddress,bytes32 changeCommitment,uint256 changeTimestamp,"
"address spender,uint256 expiry,uint256 deadline)"
);

bytes32 constant CREATE_PERMIT_1155_TYPEHASH = keccak256(
"CreatePermit1155(uint256 tokenId,address input,bytes32 inputCommitment,"
"address permitAddress,bytes32 permitCommitment,uint256 permitTimestamp,"
"address changeAddress,bytes32 changeCommitment,uint256 changeTimestamp,"
"address spender,uint256 expiry,uint256 deadline)"
);

ZK 電路規範

承諾格式

commitment = Poseidon(tokenId, amount, blinder, timestamp)

其中:

  • tokenId: uint256,公開(識別代幣類型)
  • amount: uint256,必須 < 2^96
  • blinder: 域元素(Field element),不得為 0
  • timestamp: uint256,用於防重放攻擊

與 ERC-20 的關鍵差異:tokenId 被包含在承諾中。電路強制要求轉帳中的所有輸入和輸出必須使用相同的 tokenId,防止跨代幣類型的操縱。

Amount1155 電路(鑄造/銷毀)

公開輸入:tokenId, inputCommitments[], outputCommitments[], absAmount,
isWithdraw, outputTimestamps[], txHash
私有輸入:amounts[], blinders[], timestamps[]

約束條件:

  1. 每個承諾 == Poseidon(tokenId, amount, blinder, timestamp)
  2. 所有承諾使用相同的 tokenId
  3. 鑄造:outputAmount == absAmount
  4. 銷毀:inputAmount == absAmount + changeAmount
  5. 所有數量在 [0, 2^96) 範圍內
  6. 所有 blinder ≠ 0
  7. txHash 綁定(包含 tokenId)

變體
角色
公開信號
預估約束數

Amount_0_1_1155
鑄造
6 (tokenId, commitment, amount, isWithdraw, timestamp, txHash)
~900

Amount_1_0_1155
全額銷毀
5 (tokenId, commitment, amount, isWithdraw, txHash)
~900

Amount_1_1_1155
部分銷毀
7 (tokenId, 2 commitments, amount, isWithdraw, timestamp, txHash)
~1,400

Transfer1155 電路

公開輸入:tokenId, inputCommitments[], outputCommitments[],
outputTimestamps[], txHash
私有輸入:inputAmounts[], inputBlinders[], inputTimestamps[],
outputAmounts[], outputBlinders[]

約束條件:

  1. 每個 inputCommitment == Poseidon(tokenId, inputAmount, inputBlinder, inputTimestamp)
  2. 每個 outputCommitment == Poseidon(tokenId, outputAmount, outputBlinder, outputTimestamp)
  3. 所有承諾使用相同的 tokenId(由電路強制執行)
  4. sum(inputAmounts) == sum(outputAmounts)(數量守恆)
  5. 所有數量在 [0, 2^96) 範圍內
  6. 所有 blinder ≠ 0
  7. txHash == Poseidon(tokenId, inputCommitments..., outputCommitments...)

變體
角色
預估約束數

Transfer_1_2_1155
1→2 (轉帳 + 找零)
~1,800

Transfer_2_2_1155
2→2 (標準轉帳)
~2,300

Transfer_5_1_1155
5→1 (合併)
~3,200

註:合約允許最多 MAX_INPUTS=10,但目前的電路部署支持最多 5 個輸入。更大的變體可以從相同的模板編譯。

Poseidon 參數

哈希:Poseidon
寬度:承諾使用 t = 5 (4 輸入 + 1 容量);txHash 視情況而定
輪數:RF = 8 全輪,RP = 60 部分輪
域:BN254 Fr

授權邏輯

按 tokenId 授權 —— 每個 (address, tokenId) 最多有一個授權簽名者:

function _getAuthorizedSigner(address input, uint256 tokenId) internal view returns (address) {
PolicyMeta memory pMeta = _policyMeta[input][tokenId];
PermitMeta memory tMeta = _permitMeta[input][tokenId];

if (pMeta.owner != address(0)) {    bool isActive = !pMeta.revoked && (pMeta.expiry == 0 || block.timestamp < pMeta.expiry);    return isActive ? pMeta.spender : pMeta.owner;} else if (tMeta.owner != address(0)) {    bool isActive = !tMeta.used && !tMeta.revoked        && (tMeta.expiry == 0 || block.timestamp < tMeta.expiry);    return isActive ? tMeta.spender : tMeta.owner;}return input;

}

週期清理

與隱私 ERC-20 相同:SPENT 標記編碼了 block.number,在可配置的清理窗口後可刪除。

function cleanup(address[] calldata addrs, uint256[] calldata tokenIds) external returns (uint256 cleaned);

原理闡述 (Rationale)

為何使用 4 個輸入的 Poseidon?

ERC-20 承諾使用 Poseidon(amount, blinder, timestamp) —— 3 個輸入。ERC-1155 增加了 tokenId 作為第 4 個輸入:Poseidon(tokenId, amount, blinder, timestamp)。這將承諾綁定到特定的代幣類型,防止將 100 把劍的承諾冒充為 100 瓶藥水。

電路強制要求轉帳中的所有輸入和輸出使用相同的 tokenId,因此從構造上杜絕了跨類型轉帳。

為何每次轉帳僅限單一 tokenId?

每次 transfer() 調用僅針對一個 tokenId。這保持了電路的簡單性(無需跨代幣的數量守恆)和驗證器的高效性。轉帳多種代幣類型需要多次調用 —— 這在實踐中是可以接受的,因為多類型的原子轉帳較為少見。

跨多個 tokenId 的批量鑄造透過 mintBatch() 支持,因為鑄造不需要 ZK 證明來保證數量守恆(鑄造數量是公開的)。

為何不隱藏 tokenId?

隱藏 tokenId 將需要:

  • 一個有效 tokenId 的默克爾樹(證明 tokenId 存在而不洩露它)

  • 跨類型守恆證明(電路複雜度大幅增加)

  • 隱藏供應量追蹤(與大多數合規要求不相容)

對於大多數使用場景(遊戲道具、忠誠度積分、門票)來說,被轉帳的代幣類型並不敏感,隱藏它的收益微乎其微。保持 tokenId 公開極大地簡化了協議。

為何每個 (address, tokenId) 使用一個 SPENT_MARKER?

單個地址可以持有不同的 tokenId。支出一個 tokenId 不應影響其他 tokenId。SPENT 標記是按 (address, tokenId) 對設置的,允許獨立的生命週期管理。

性能 (Performance)

預估 Gas 消耗(使用模擬驗證器 —— 生產環境請為每個 Groth16 驗證增加約 200K):

操作
Gas
備註

mint (單個)
~320–360K
單一 tokenId

mintBatch (5 個 tokenId)
~1.4–1.6M
一筆交易 5 個 tokenId

burn (帶找零)
~350–390K
部分銷毀

transfer (1→2)
~370–410K
1 輸入, 2 輸出

transfer (2→2)
~420–460K
標準轉帳

consolidate (5→1)
~500–550K
合併 5 個 VOSA

createPolicy
~410–460K
按 tokenId

revokePolicy
~30–35K

由於承諾計算中增加了 tokenId 欄位(4 輸入 Poseidon 對比 3 輸入),電路約束數量比 ERC-20 等效項高出約 15%。

向後兼容性 (Backwards Compatibility)

本標準實現 ERC-1155 接口(如 balanceOf(address,uint256), safeTransferFrom 等)。它是一個獨立的隱私保護多代幣標準。保留了 uri() 函數以實現元數據兼容性。

安全考量 (Security Considerations)

跨代幣類型攻擊防禦

電路強制要求轉帳中的所有承諾使用相同的 tokenId。這在 ZK 證明內部進行驗證 —— 無法在不使證明失效的情況下混合代幣類型。

可信設置 (Trusted Setup)

與隱私 ERC-20 相同:Groth16 每個電路變體都需要一個可信設置儀式。

搶跑保護 (Front-Running Protection)

EIP-712 簽名綁定了 tokenId 和所有可變參數。針對 tokenId=42 的簽名無法在 tokenId=7 上重放。

雙花 (Double-Spending)

使用與隱私 ERC-20 相同的 O(1) SPENT_MARKER 機制,但以 (address, tokenId) 為索引。

數量安全

範圍證明強制執行 0 ≤ amount < 2^96。數量守恆在 ZK 電路中按 tokenId 執行。

批量鑄造原子性

mintBatch() 是原子的 —— 要麼所有 tokenId 都鑄造成功,要麼都不成功。每個 tokenId 都有自己的承諾和 ZK 證明。

參考實現 (Reference Implementation)

nft-native/
├── contracts/
│ ├── src/
│ │ ├── PrivateERC1155.sol # 主合約 (約 1160 行)
│ │ ├── libraries/
│ │ │ └── PublicInputBuilder.sol # ZK 公開輸入構造輔助工具
│ │ ├── interfaces/
│ │ │ ├── IGroth16Verifier.sol
│ │ │ └── IPoseidon.sol
│ │ └── mocks/
│ │ ├── MockVerifier.sol
│ │ └── MockPoseidon.sol
│ └── test/
│ └── PrivateERC1155.test.ts
├── circuits/
│ ├── src/
│ │ ├── commitment1155.circom # Poseidon(tokenId, amount, blinder, ts)
│ │ ├── amount1155.circom # 鑄造/銷毀電路 (0→1, 1→0, 1→1)
│ │ ├── transfer1155.circom # 轉帳電路 (N→M)
│ │ └── amount_0_1_main.circom # 鑄造電路入口點
│ └── lib/
│ ├── poseidon.circom # circomlib Poseidon
│ └── comparators.circom # circomlib 比較器 + bitify
└── circuits/scripts/
├── compile.sh # 電路編譯
└── test.sh # Witness + 證明生成測試

討論問題

  • 每次轉帳單一 tokenId:這是否可以接受?或者標準是否應該支持原子的多 tokenId 轉帳(代價是電路複雜度大幅增加)?

  • 批量操作:transferBatch()(一次調用轉帳多個 tokenId)是否應該成為標準的一部分,還是順序調用 transfer() 就足夠了?

  • tokenId 可見性:是否存在某些場景,隱藏代幣類型的重要性足以抵消電路複雜度的增加?

  • 元數據隱私:目前的 uri() 是公開的。是否應該有一種機制為每個持有者提供加密的元數據?

  • 與 ERC-1155 的互操作性:是否應該提供一個 CompatibleERC1155 變體(類似 CompatibleERC20),具備公開餘額 + 隱私模式切換功能?

版權

透過 放棄版權及相關權利。

        1 則貼文 - 1 位參與者        [閱讀完整主題](https://ethereum-magicians.org/t/draft-erc-private-erc-1155-privacy-preserving-multi-token-standard/27894)