Soulbound Token 與去中心化身份完整指南:以太坊鏈上身份驗證、信誉系统與 DID 技術深度解析

Soulbound Token(SBT)是以太坊創始人 Vitalik Buterin 提出的概念,旨在創建不可轉讓但可撤銷的「靈魂綁定」代幣,用於代表個人身份、資格、成就和社會關係。本文深入分析 SBT 的技術標準、ERC-5192 規範、與 DID(去中心化身份)的整合、在 DAO 治理、信誉系统和社交網路中的應用,以及 2026 年的最新發展與監管考量。

Soulbound Token 與去中心化身份完整指南:以太坊鏈上身份驗證、聲譽系統與 DID 技術深度解析

概述

Soulbound Token(SBT)是以太坊創始人 Vitalik Buterin 在 2022 年提出的革命性概念,旨在創建一種不可轉讓但可撤銷的「靈魂綁定」代幣,用於代表個人身份、資格、成就和社會關係。這種代幣類型將區塊鏈的代幣經濟學與現實世界的身份系統相結合,為去中心化身份(Decentralized Identity, DID)和聲譽經濟奠定了技術基礎。

截至 2026 年第一季度,SBT 和 DID 技術已在 DAO 治理、專業認證、社交網路、遊戲成就等場景得到廣泛應用。本文深入分析 SBT 的技術標準(ERC-5192)、與 W3C DID 規範的整合、在以太坊生態中的實際應用案例,以及面臨的隱私和監管挑戰。


第一章:去中心化身份理論框架

1.1 身份的基本概念

1.1.1 身份的定義與組成

身份(Identity)在數位世界中指的是用於識別和描述實體(個人、組織、設備)的屬性集合:

身份的構成要素

要素類別說明範例
識別符用於唯一標識實體姓名、DID、錢包地址
屬性描述實體的特徵年齡、職業、學歷
關係實體之間的連接僱傭關係、會員資格
憑證第三方對屬性的驗證護照、專業執照
聲譽基於歷史行為的評價信用評分、評論

傳統身份 vs 去中心化身份

維度傳統中心化身份去中心化身份
控制權中心化機構個人錢包
資料存儲機構伺服器區塊鏈 + 去中心化存儲
驗證方式機構背書密碼學驗證
攜帶性低(需重新認證)高(便攜 DID)
隱私性可選擇性披露
抗審查性

1.1.2 去中心化身份的需求

現有身份系統的問題

  1. 資料孤島:各平台獨立管理身份資料,用户需重複驗證
  2. 隱私洩露:中心化機構可訪問全部資料
  3. 單點故障:機構被攻擊或倒閉導致身份丟失
  4. 歧視性定價:保險、金融機構根據全面資料歧視定價
  5. 虛假身份:缺乏可靠的身份驗證機制

區塊鏈提供的解決方案

區塊鏈特性對身份的意義
不可竄改性身份屬性無法偽造
抗審查性身份無法被撤銷
密碼學所有權個人完全控制身份
可驗證性第三方可驗證聲譽
互通性跨平台身份便攜

1.2 DID 標準與規範

1.2.1 W3C DID 規範

W3C(World Wide Web Consortium)於 2022 年發布了去中心化識別符(DID)規範:

DID 格式

did:method:method-specific-identifier

範例:
did:ethr:0x1234...abcd        # 以太坊地址
did:key:z6Mkfri...           # 公共密鑰
did:web:example.com           # 域名
did:ion:EiA...                # Bitcoin SID

DID 文件結構

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://www.w3.org/ns/did/v2"
  ],
  "id": "did:ethr:0x1234567890123456789012345678901234567890",
  "verificationMethod": [{
    "id": "did:ethr:0x123...#controller",
    "type": "EcdsaSecp256k1RecoveryMethod2020",
    "controller": "did:ethr:0x123...",
    "publicKeyHex": "0x1234567890..."
  }],
  "authentication": ["did:ethr:0x123...#controller"],
  "service": [{
    "id": "did:ethr:0x123...#linked-domains",
    "type": "LinkedDomains",
    "serviceEndpoint": "https://app.example.com"
  }]
}

1.2.2 可驗證憑證(Verifiable Credentials)

W3C VC(Verifiable Credentials)是 DID 系統中用於表達和驗證聲譽的標準:

{
  "@context": [
    "https://www.w3.org/2018/credentials/v1",
    "https://www.w3.org/2018/credentials/examples/v1"
  ],
  "id": "urn:uuid:3978344f-8596-4c3a-9192-8f8e8e8",
  "type": ["VerifiableCredential", "UniversityDegreeCredential"],
  "issuer": {
    "id": "did:ethr:0xabcd...1234"
  },
  "issuanceDate": "2026-03-15T10:00:00Z",
  "credentialSubject": {
    "id": "did:ethr:0x5678...4321",
    "degree": {
      "type": "BachelorDegree",
      "name": "Bachelor of Science in Computer Science"
    }
  },
  "proof": {
    "type": "EcdsaSecp256k1Signature2019",
    "created": "2026-03-15T10:00:00Z",
    "proofPurpose": "assertionMethod",
    "verificationMethod": "did:ethr:0xabcd...1234#controller",
    "signatureValue": "Kx..."
  }
}

第二章:Soulbound Token 技術標準

2.1 ERC-5192 規範詳解

2.1.1 SBT 的基本定義

ERC-5192 定義了 Soulbound Token 的最小介面:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title ERC-5192 Soul Bound Token
 * @notice Interface for Soulbound Tokens (SBTs)
 * @dev This interface extends EIP-165 to identify SBT interfaces
 */
interface IERC5192 {
    /**
     * @notice Emitted when the lock status changes
     * @param tokenId The token for which the lock status changed
     * @param locked Boolean value indicating the new lock status
     */
    event Locked(uint256 indexed tokenId, bool locked);
    
    /**
     * @notice Returns the lock status of the token
     * @param tokenId The token to query the lock status for
     * @return bool True if the token is locked (soulbound), false otherwise
     */
    function locked(uint256 tokenId) external view returns (bool);
}

2.1.2 完整 SBT 合約實現

// ERC-5192 Soulbound Token Implementation
contract SoulboundToken is IERC5192, IERC165 {
    // Token metadata
    string public name;
    string public symbol;
    
    // Token state
    mapping(uint256 => address) public ownerOf;
    mapping(uint256 => string) public tokenURIs;
    mapping(uint256 => bool) public locked;  // Soulbound status
    
    // 追蹤每個地址持有的 SBT 數量(用於查詢)
    mapping(address => uint256[]) public ownedTokens;
    
    // 合約狀態
    address public issuer;  // 發行者地址
    bool public isSoulbound;  // 全域 SBT 標誌
    
    // 枚舉索引
    mapping(address => mapping(uint256 => uint256)) public ownedTokensIndex;
    
    event Transfer(
        address indexed from, 
        address indexed to, 
        uint256 indexed tokenId
    );
    
    event Locked(uint256 indexed tokenId, bool locked);
    
    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
        issuer = msg.sender;
        isSoulbound = true;
    }
    
    /**
     * @notice Mint a new Soulbound Token
     * @param to The address that will own the SBT
     * @param tokenId The token ID to mint
     * @param uri The URI for the token metadata
     */
    function mint(
        address to, 
        uint256 tokenId, 
        string calldata uri
    ) external onlyIssuer {
        require(ownerOf[tokenId] == address(0), "Token already exists");
        require(to != address(0), "Invalid recipient");
        
        // Mint token
        ownerOf[tokenId] = to;
        tokenURIs[tokenId] = uri;
        locked[tokenId] = true;  // Soulbound = locked
        
        // Update enumeration
        _addTokenToOwnerEnumeration(to, tokenId);
        
        emit Transfer(address(0), to, tokenId);
        emit Locked(tokenId, true);
    }
    
    /**
     * @notice Burn a Soulbound Token (can only be called by issuer)
     * @param tokenId The token ID to burn
     */
    function burn(uint256 tokenId) external onlyIssuer {
        address owner = ownerOf[tokenId];
        require(owner != address(0), "Token does not exist");
        
        // Update state
        delete ownerOf[tokenId];
        delete tokenURIs[tokenId];
        delete locked[tokenId];
        
        // Update enumeration
        _removeTokenFromOwnerEnumeration(owner, tokenId);
        
        emit Transfer(owner, address(0), tokenId);
        emit Locked(tokenId, false);
    }
    
    /**
     * @notice Revoke a SBT (transfer to issuer, releasing soulbound status)
     * @param tokenId The token ID to revoke
     */
    function revoke(uint256 tokenId) external {
        address owner = ownerOf[tokenId];
        require(owner == msg.sender, "Not the owner");
        
        // Remove from owner
        _removeTokenFromOwnerEnumeration(owner, tokenId);
        ownerOf[tokenId] = address(0);
        locked[tokenId] = false;
        
        emit Transfer(owner, address(0), tokenId);
        emit Locked(tokenId, false);
    }
    
    /**
     * @notice Get lock status of a token (ERC-5192)
     * @param tokenId The token ID to query
     * @return bool True if locked (soulbound)
     */
    function locked(uint256 tokenId) external view override returns (bool) {
        require(ownerOf[tokenId] != address(0), "Token does not exist");
        return locked[tokenId];
    }
    
    /**
     * @notice Get all SBTs owned by an address
     * @param owner The address to query
     * @return uint256[] Array of token IDs
     */
    function tokensOf(address owner) 
        external 
        view 
        returns (uint256[] memory) 
    {
        return ownedTokens[owner];
    }
    
    // ============ Internal Functions ============
    
    function _addTokenToOwnerEnumeration(
        address to, 
        uint256 tokenId
    ) internal {
        ownedTokens[to].push(tokenId);
        ownedTokensIndex[to][tokenId] = ownedTokens[to].length - 1;
    }
    
    function _removeTokenFromOwnerEnumeration(
        address from, 
        uint256 tokenId
    ) internal {
        uint256 lastTokenIndex = ownedTokens[from].length - 1;
        uint256 tokenIndex = ownedTokensIndex[from][tokenId];
        
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = ownedTokens[from][lastTokenIndex];
            ownedTokens[from][tokenIndex] = lastTokenId;
            ownedTokensIndex[from][lastTokenId] = tokenIndex;
        }
        ownedTokens[from].pop();
    }
    
    modifier onlyIssuer() {
        require(msg.sender == issuer, "Only issuer can call");
        _;
    }
    
    // ============ Interface Support ============
    
    function supportsInterface(bytes4 interfaceId) 
        public 
        view 
        override 
        returns (bool) 
    {
        return 
            interfaceId == type(IERC5192).interfaceId ||
            interfaceId == type(IERC165).interfaceId;
    }
    
    /**
     * @notice Standard transfer - will revert for soulbound tokens
     * @dev This override ensures soulbound tokens cannot be transferred
     */
    function transferFrom(
        address from, 
        address to, 
        uint256 tokenId
    ) public virtual {
        require(
            locked[tokenId] == false, 
            "Soulbound: transfer not allowed"
        );
        // If not locked, standard ERC-721 transfer logic applies
        _transfer(from, to, tokenId);
    }
    
    function _transfer(
        address from, 
        address to, 
        uint256 tokenId
    ) internal virtual {
        // Standard ERC-721 transfer logic
        require(ownerOf[tokenId] == from, "Incorrect owner");
        require(to != address(0), "Transfer to zero address");
        
        // Clear approval
        delete _tokenApprovals[tokenId];
        
        // Update state
        _removeTokenFromOwnerEnumeration(from, tokenId);
        _addTokenToOwnerEnumeration(to, tokenId);
        ownerOf[tokenId] = to;
        
        emit Transfer(from, to, tokenId);
    }
}

2.2 SBT 的進階功能

2.2.1 可撤銷 SBT

/**
 * 可撤銷的 SBT 合約
 * 允許發行者在特定條件下撤銷 SBT
 */
contract RevocableSBT is SoulboundToken {
    // 撤銷記錄
    mapping(uint256 => bool) public revoked;
    mapping(uint256 => uint256) public revocationTime;
    
    // 撤銷原因
    mapping(uint256 => string) public revocationReason;
    
    event Revoked(
        uint256 indexed tokenId,
        address indexed issuer,
        string reason
    );
    
    /**
     * @notice Revoke a SBT
     * @param tokenId Token ID to revoke
     * @param reason Reason for revocation
     */
    function revokeSBT(
        uint256 tokenId, 
        string calldata reason
    ) external onlyIssuer {
        require(!revoked[tokenId], "Already revoked");
        
        revoked[tokenId] = true;
        revocationTime[tokenId] = block.timestamp;
        revocationReason[tokenId] = reason;
        
        emit Revoked(tokenId, msg.sender, reason);
    }
    
    /**
     * @notice Check if a SBT is valid (not revoked)
     * @param tokenId Token ID to check
     * @return bool True if valid and not revoked
     */
    function isValid(uint256 tokenId) public view returns (bool) {
        return 
            ownerOf[tokenId] != address(0) && 
            locked[tokenId] &&
            !revoked[tokenId];
    }
}

2.2.2 階層式 SBT

/**
 * 階層式 SBT 系統
 * SBT 可以形成階層結構(例如:學位階層)
 */
contract HierarchicalSBT is SoulboundToken {
    // 階層結構
    struct SBTLevel {
        uint8 level;           // 階層等級
        string levelName;      // 等級名稱
        uint256 prerequisite;   // 前置 SBT tokenId(0 表示無前置)
    }
    
    mapping(uint256 => SBTLevel) public sbtLevels;
    mapping(uint256 => uint256) public parentToken;  // 父 SBT tokenId
    mapping(uint256 => uint256[]) public childTokens;  // 子 SBT tokenIds
    
    /**
     * @notice Mint a hierarchical SBT
     * @param to Recipient address
     * @param tokenId New token ID
     * @param level Level information
     * @param parentId Parent SBT tokenId
     * @param uri Token URI
     */
    function mintHierarchicalSBT(
        address to,
        uint256 tokenId,
        SBTLevel memory level,
        uint256 parentId,
        string calldata uri
    ) external onlyIssuer {
        // 驗證前置條件
        if (level.prerequisite > 0) {
            require(
                ownerOf[level.prerequisite] == to,
                "Prerequisite SBT not owned"
            );
        }
        
        // 驗證父 SBT(如果存在)
        if (parentId > 0) {
            require(
                ownerOf[parentId] == to,
                "Parent SBT not owned"
            );
            childTokens[parentId].push(tokenId);
        }
        
        parentToken[tokenId] = parentId;
        sbtLevels[tokenId] = level;
        
        mint(to, tokenId, uri);
    }
    
    /**
     * @notice Verify SBT hierarchy is valid
     * @param tokenId Root token ID
     * @return bool True if hierarchy is valid
     */
    function verifyHierarchy(uint256 tokenId) 
        public 
        view 
        returns (bool) 
    {
        uint256 current = tokenId;
        uint8 depth = 0;
        uint8 maxDepth = 10;
        
        while (current > 0 && depth < maxDepth) {
            if (!isValid(current)) {
                return false;
            }
            current = parentToken[current];
            depth++;
        }
        
        return true;
    }
}

第三章:去中心化身份系統架構

3.1 ENS 作為身份基礎

3.1.1 ENS 域名系統

以太坊名稱服務(ENS)是目前最成功的以太坊原生身份系統:

ENS 域名結構

主域名格式:alice.eth
子域名格式:mail.alice.eth
解析目標:區塊鏈地址、內容哈希、介面描述

ENS 註冊流程

/**
 * ENS 註冊合約介面
 */
interface IENSRegistrar {
    // 註冊域名
    function register(
        bytes32 label,      // 標籤哈希
        address owner,      // 所有者地址
        uint256 duration    // 註冊時長(秒)
    ) external payable returns (uint256);
    
    // renewal 域名
    function renew(
        bytes32 label, 
        uint256 duration
    ) external payable;
    
    // 轉移域名所有權
    function transfer(
        address newOwner,
        uint256 tokenId
    ) external;
    
    // 查詢域名到期時間
    function nameExpires(uint256 tokenId) 
        external 
        view 
        returns (uint256);
}

/**
 * ENS 解析器介面
 */
interface IResolver {
    // 解析地址
    function addr(bytes32 node) 
        external 
        view 
        returns (address);
    
    // 設置地址
    function setAddr(
        bytes32 node, 
        address addr
    ) external;
    
    // 解析內容哈希
    function contenthash(bytes32 node) 
        external 
        view 
        returns (bytes memory);
    
    // 設置文本記錄
    function setText(
        bytes32 node, 
        string calldata key, 
        string calldata value
    ) external;
    
    // 獲取文本記錄
    function text(
        bytes32 node, 
        string calldata key
    ) external 
        view 
        returns (string memory);
}

3.1.2 ENS 身份屬性擴展

/**
 * ENS 身份屬性合約
 * 為 ENS 域名添加豐富的身份屬性
 */
contract ENSIdentityRegistry {
    // ENS 解析器
    IENS public ens;
    bytes32 public rootNode;
    
    // 身份屬性結構
    struct IdentityAttribute {
        string key;       // 屬性鍵
        bytes value;       // 屬性值(加密)
        uint256 timestamp; // 添加時間
        bool verified;     // 是否經過驗證
    }
    
    // 域名 -> 屬性列表
    mapping(bytes32 => IdentityAttribute[]) public identityAttributes;
    
    // 已驗證的發布者
    mapping(address => bool) public verifiedIssuers;
    
    event AttributeAdded(
        bytes32 indexed node,
        string key,
        address issuer
    );
    
    event AttributeVerified(
        bytes32 indexed node,
        string key,
        address verifier
    );
    
    constructor(address _ens, bytes32 _rootNode) {
        ens = IENS(_ens);
        rootNode = _rootNode;
    }
    
    /**
     * @notice 添加身份屬性
     * @param node ENS 節點
     * @param key 屬性鍵
     * @param value 屬性值(加密)
     */
    function addAttribute(
        bytes32 node,
        string calldata key,
        bytes calldata value
    ) external {
        require(
            msg.sender == ens.owner(node),
            "Not the domain owner"
        );
        
        identityAttributes[node].push(IdentityAttribute({
            key: key,
            value: value,
            timestamp: block.timestamp,
            verified: false
        }));
        
        emit AttributeAdded(node, key, msg.sender);
    }
    
    /**
     * @notice 驗證身份屬性(由驗證發布者)
     * @param node ENS 節點
     * @param keyIndex 屬性索引
     */
    function verifyAttribute(
        bytes32 node,
        uint256 keyIndex
    ) external {
        require(
            verifiedIssuers[msg.sender],
            "Not a verified issuer"
        );
        
        require(
            keyIndex < identityAttributes[node].length,
            "Invalid index"
        );
        
        identityAttributes[node][keyIndex].verified = true;
        
        emit AttributeVerified(node, 
            identityAttributes[node][keyIndex].key, 
            msg.sender
        );
    }
    
    /**
     * @notice 批量添加身份屬性
     */
    function batchAddAttributes(
        bytes32 node,
        string[] calldata keys,
        bytes[] calldata values
    ) external {
        require(keys.length == values.length, "Length mismatch");
        require(
            msg.sender == ens.owner(node),
            "Not the domain owner"
        );
        
        for (uint256 i = 0; i < keys.length; i++) {
            identityAttributes[node].push(IdentityAttribute({
                key: keys[i],
                value: values[i],
                timestamp: block.timestamp,
                verified: false
            }));
            
            emit AttributeAdded(node, keys[i], msg.sender);
        }
    }
    
    /**
     * @notice 查詢已驗證的屬性
     */
    function getVerifiedAttributes(
        bytes32 node
    ) external view returns (IdentityAttribute[] memory) {
        IdentityAttribute[] storage all = identityAttributes[node];
        uint256 count = 0;
        
        // Count verified attributes
        for (uint256 i = 0; i < all.length; i++) {
            if (all[i].verified) count++;
        }
        
        // Build result array
        IdentityAttribute[] memory result = new IdentityAttribute[](count);
        uint256 index = 0;
        for (uint256 i = 0; i < all.length; i++) {
            if (all[i].verified) {
                result[index] = all[i];
                index++;
            }
        }
        
        return result;
    }
}

3.2 Worldcoin 與生物特徵身份

3.2.1 World ID 技術架構

Worldcoin 採用零知識證明來實現生物特徵身份驗證,同時保護用戶隱私:

系統架構

┌─────────────────────────────────────────────────────────────────┐
│                    Worldcoin 身份驗證架構                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────┐                                            │
│  │   Orb 設備      │                                            │
│  │  (虹膜掃描)     │                                            │
│  └────────┬────────┘                                            │
│           │                                                     │
│           ▼                                                     │
│  ┌─────────────────┐                                            │
│  │  虹膜承諾       │                                            │
│  │ (不存儲原圖)    │                                            │
│  └────────┬────────┘                                            │
│           │                                                     │
│           ▼                                                     │
│  ┌─────────────────┐                                            │
│  │  虹膜代碼       │                                            │
│  │  (唯一識別符)   │                                            │
│  └────────┬────────┘                                            │
│           │                                                     │
│           ▼                                                     │
│  ┌─────────────────┐     ┌─────────────────┐                    │
│  │  Semaphore 承諾  │────▶│  World ID 合約  │                    │
│  │  (ZK Proof)      │     │  (以太坊)       │                    │
│  └─────────────────┘     └─────────────────┘                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Semaphore 零知識身份系統

/**
 * World ID 身份承諾合約
 * 基於 Semaphore 協議
 */
contract WorldIdContract {
    // 身份承諾
    struct IdentityCommitment {
        address owner;
        bytes32 commitment;     // 承諾哈希
        uint256 leafIndex;      // Merkle 樹葉節點索引
        bool status;            // true = 已註冊
    }
    
    // Merkle 樹根
    mapping(uint256 => bool) public registeredRoots;
    mapping(address => IdentityCommitment) public identityCommitments;
    
    // 訊號承諾
    struct Signal {
        address caller;
        uint256 signal;
        uint256 nullifierHash;
        uint256 externalNullifier;
        uint256[8] proof;
    }
    
    // 已使用的 nullifier(防止雙重驗證)
    mapping(bytes32 => bool) public nullifierHashes;
    
    event IdentityRegistered(
        address indexed owner,
        bytes32 indexed commitment,
        uint256 leafIndex
    );
    
    event ProofVerified(
        address indexed signal,
        bytes32 indexed nullifierHash
    );
    
    /**
     * @notice 註冊新身份
     * @param commitment 身份承諾
     * @param merkleProof Merkle 證明
     */
    function registerIdentity(
        bytes32 commitment,
        uint256[20] calldata merkleProof
    ) external {
        require(
            identityCommitments[msg.sender].status == false,
            "Already registered"
        );
        
        // 驗證 Merkle 證明
        uint256 leafIndex = _verifyMerkleProof(
            commitment,
            merkleProof
        );
        
        require(leafIndex > 0, "Invalid proof");
        
        // 存儲承諾
        identityCommitments[msg.sender] = IdentityCommitment({
            owner: msg.sender,
            commitment: commitment,
            leafIndex: leafIndex,
            status: true
        });
        
        emit IdentityRegistered(msg.sender, commitment, leafIndex);
    }
    
    /**
     * @notice 驗證零知識證明
     * @param signal 訊號(通常是地址或其他)
     * @param root Merkle 樹根
     * @param nullifierHash Nullifier 哈希
     * @param externalNullifier 外部 nullifier
     * @param proof ZK 證明 (Groth16)
     */
    function verifyProof(
        address signal,
        uint256 root,
        bytes32 nullifierHash,
        uint256 externalNullifier,
        uint256[8] calldata proof
    ) external {
        // 驗證根是否已註冊
        require(
            registeredRoots[root],
            "Invalid merkle root"
        );
        
        // 驗證 nullifier 未使用
        require(
            !nullifierHashes[nullifierHash],
            "Nullifier already used"
        );
        
        // 驗證 ZK 證明(使用 zkSNARK 驗證器)
        require(
            _verifyGroth16Proof(
                signal,
                root,
                nullifierHash,
                externalNullifier,
                proof
            ),
            "Invalid proof"
        );
        
        // 標記 nullifier 為已使用
        nullifierHashes[nullifierHash] = true;
        
        emit ProofVerified(signal, nullifierHash);
    }
    
    /**
     * @notice 添加有效的 Merkle 根
     * @param root Merkle 樹根
     */
    function addRoot(uint256 root) external onlyOwner {
        registeredRoots[root] = true;
    }
    
    function _verifyMerkleProof(
        bytes32 commitment,
        uint256[20] calldata proof
    ) internal pure returns (uint256) {
        // Merkle 驗證邏輯
        return 1;  // 簡化實現
    }
    
    function _verifyGroth16Proof(
        address signal,
        uint256 root,
        bytes32 nullifierHash,
        uint256 externalNullifier,
        uint256[8] calldata proof
    ) internal view returns (bool) {
        // Groth16 驗證邏輯
        // 調用預編譯合約或外部驗證器
        return true;  // 簡化實現
    }
}

第四章:SBT 應用場景深度分析

4.1 DAO 治理與聲譽

4.1.1 聲譽加權治理

傳統的代幣加權投票容易受到 Sybil 攻擊。SBT 提供了一種新的聲譽加權治理方案:

/**
 * 基於 SBT 的聲譽治理系統
 */
contract SBTWeightedGovernance {
    // 治理代幣
    IERC20 public governanceToken;
    
    // SBT 合約引用
    ISoulboundToken public sbtContract;
    
    // 聲譽權重配置
    struct ReputationWeights {
        uint256 workReputation;    // 工作經歷權重
        uint256 educationReputation; // 教育背景權重
        uint256 contributionReputation; // 貢獻權重
    }
    
    ReputationWeights public weights;
    
    // 提案結構
    struct Proposal {
        bytes32 descriptionHash;
        uint256 votingDeadline;
        uint256 yesVotes;
        uint256 noVotes;
        bool executed;
        bool cancelled;
    }
    
    mapping(uint256 => Proposal) public proposals;
    
    event ProposalCreated(
        uint256 indexed proposalId,
        address proposer,
        bytes32 descriptionHash
    );
    
    event VoteCast(
        uint256 indexed proposalId,
        address voter,
        bool support,
        uint256 weight
    );
    
    constructor(
        address _governanceToken,
        address _sbtContract
    ) {
        governanceToken = IERC20(_governanceToken);
        sbtContract = ISoulboundToken(_sbtContract);
        
        // 設置默認權重
        weights = ReputationWeights({
            workReputation: 30,      // 30%
            educationReputation: 20,  // 20%
            contributionReputation: 50 // 50%
        });
    }
    
    /**
     * @notice 計算地址的治理權重
     * @param voter 投票者地址
     * @return uint256 治理權重
     */
    function calculateVotingWeight(address voter) 
        public 
        view 
        returns (uint256) 
    {
        // 1. 代幣餘額(最低權重)
        uint256 tokenWeight = governanceToken.balanceOf(voter) 
            / 1e18 
            * 10;  // 每 1 ETH = 10 權重
        
        // 2. SBT 權重
        uint256 sbtWeight = _calculateSBTWeight(voter);
        
        // 3. 總權重(防範代幣囤積)
        return tokenWeight + sbtWeight;
    }
    
    /**
     * @notice 計算 SBT 聲譽權重
     */
    function _calculateSBTWeight(address voter) 
        internal 
        view 
        returns (uint256) 
    {
        uint256 totalWeight = 0;
        uint256[] memory tokens = sbtContract.tokensOf(voter);
        
        for (uint256 i = 0; i < tokens.length; i++) {
            // 根據 SBT 類型計算權重
            string memory tokenType = sbtContract.getTokenType(tokens[i]);
            
            if (keccak256(bytes(tokenType)) == keccak256(bytes("WORK"))) {
                totalWeight += weights.workReputation;
            } else if (
                keccak256(bytes(tokenType)) == keccak256(bytes("EDUCATION"))
            ) {
                totalWeight += weights.educationReputation;
            } else if (
                keccak256(bytes(tokenType)) == keccak256(bytes("CONTRIBUTION"))
            ) {
                totalWeight += weights.contributionReputation;
            }
        }
        
        return totalWeight;
    }
    
    /**
     * @notice 創建提案
     */
    function createProposal(
        bytes32 descriptionHash
    ) external returns (uint256 proposalId) {
        proposalId = proposals.length;
        
        proposals[proposalId] = Proposal({
            descriptionHash: descriptionHash,
            votingDeadline: block.timestamp + 7 days,
            yesVotes: 0,
            noVotes: 0,
            executed: false,
            cancelled: false
        });
        
        emit ProposalCreated(proposalId, msg.sender, descriptionHash);
    }
    
    /**
     * @notice 投票
     */
    function castVote(
        uint256 proposalId,
        bool support
    ) external {
        Proposal storage proposal = proposals[proposalId];
        
        require(
            block.timestamp < proposal.votingDeadline,
            "Voting ended"
        );
        require(!proposal.executed, "Already executed");
        
        uint256 weight = calculateVotingWeight(msg.sender);
        require(weight > 0, "No voting power");
        
        if (support) {
            proposal.yesVotes += weight;
        } else {
            proposal.noVotes += weight;
        }
        
        emit VoteCast(proposalId, msg.sender, support, weight);
    }
    
    /**
     * @notice 執行提案
     */
    function executeProposal(uint256 proposalId) external {
        Proposal storage proposal = proposals[proposalId];
        
        require(
            block.timestamp >= proposal.votingDeadline,
            "Voting not ended"
        );
        require(!proposal.executed, "Already executed");
        require(!proposal.cancelled, "Cancelled");
        require(
            proposal.yesVotes > proposal.noVotes,
            "Proposal failed"
        );
        
        proposal.executed = true;
        
        // 執行提案邏輯(呼叫目標合約等)
        _executeProposalActions(proposalId);
    }
}

4.1.2 Sybil 抵抗機制

/**
 * Sybil 抵抗合約
 * 使用 SBT 作為身份驗證
 */
contract SybilResistant {
    // 最低聲譽閾值
    uint256 public minimumReputationScore;
    
    // 聲譽計算合約
    IReputationOracle public reputationOracle;
    
    // 已驗證用戶
    mapping(address => bool) public verifiedUsers;
    
    // 用戶聲譽分數
    mapping(address => uint256) public reputationScores;
    
    // 時間鎖(防止快速創建多個身份)
    mapping(address => uint256) public registrationTime;
    uint256 public cooldownPeriod = 1 days;
    
    event UserVerified(
        address indexed user,
        uint256 reputationScore
    );
    
    constructor(
        uint256 _minimumReputationScore,
        address _reputationOracle
    ) {
        minimumReputationScore = _minimumReputationScore;
        reputationOracle = IReputationOracle(_reputationOracle);
    }
    
    /**
     * @notice 驗證用戶身份
     * @param sbtTokenIds SBT token IDs 用於驗證
     * @param proof ZK 證明
     */
    function verifyUser(
        uint256[] calldata sbtTokenIds,
        bytes calldata proof
    ) external returns (bool) {
        require(
            block.timestamp >= registrationTime[msg.sender] + cooldownPeriod,
            "Cooldown period not elapsed"
        );
        
        // 1. 驗證 SBT 所有權
        require(
            _verifySBTOwnership(msg.sender, sbtTokenIds),
            "Invalid SBT ownership"
        );
        
        // 2. 計算聲譽分數
        uint256 score = reputationOracle.calculateScore(
            msg.sender,
            sbtTokenIds
        );
        
        require(
            score >= minimumReputationScore,
            "Reputation below minimum"
        );
        
        // 3. 驗證 ZK 證明(如果是 World ID)
        require(
            _verifyProof(msg.sender, proof),
            "Invalid proof"
        );
        
        // 4. 標記為已驗證
        verifiedUsers[msg.sender] = true;
        reputationScores[msg.sender] = score;
        registrationTime[msg.sender] = block.timestamp;
        
        emit UserVerified(msg.sender, score);
        
        return true;
    }
    
    /**
     * @notice 檢查用戶是否已驗證
     */
    function isVerified(address user) external view returns (bool) {
        return verifiedUsers[user];
    }
    
    /**
     * @notice 獲取用戶聲譽分數
     */
    function getReputation(address user) external view returns (uint256) {
        return reputationScores[user];
    }
    
    function _verifySBTOwnership(
        address user,
        uint256[] calldata tokenIds
    ) internal view returns (bool) {
        // 驗證每個 SBT 是否由 user 持有
        for (uint256 i = 0; i < tokenIds.length; i++) {
            if (sbtContract.ownerOf(tokenIds[i]) != user) {
                return false;
            }
        }
        return true;
    }
    
    function _verifyProof(
        address user,
        bytes calldata proof
    ) internal pure returns (bool) {
        // ZK 證明驗證邏輯
        return true;  // 簡化實現
    }
}

4.2 專業認證與資格

4.2.1 專業執照系統

/**
 * 專業資格認證 SBT 合約
 */
contract ProfessionalCredentials {
    // 專業領域定義
    struct CredentialType {
        string name;           // 領域名稱
        uint256 validityPeriod; // 有效期(秒)
        uint256 renewalCredits; // 更新所需積分
        bool requiresExam;      // 是否需要考試
    }
    
    mapping(bytes32 => CredentialType) public credentialTypes;
    mapping(address => mapping(bytes32 => Credential)) public credentials;
    
    struct Credential {
        uint256 issueDate;
        uint256 expiryDate;
        uint256 renewalCredits;
        bytes32 issuerOrg;
        string credentialHash;  // IPFS 存儲的詳細資訊
        bool revoked;
    }
    
    // 授權發證機構
    mapping(address => bool) public authorizedIssuers;
    
    event CredentialIssued(
        address indexed holder,
        bytes32 indexed credentialType,
        address indexed issuer,
        uint256 expiryDate
    );
    
    event CredentialRevoked(
        address indexed holder,
        bytes32 indexed credentialType,
        address indexed issuer,
        string reason
    );
    
    /**
     * @notice 發放專業資格
     */
    function issueCredential(
        address holder,
        bytes32 credentialType,
        uint256 validityPeriod,
        string calldata credentialHash
    ) external onlyAuthorizedIssuer {
        require(
            credentials[holder][credentialType].issueDate == 0,
            "Credential already exists"
        );
        
        credentials[holder][credentialType] = Credential({
            issueDate: block.timestamp,
            expiryDate: block.timestamp + validityPeriod,
            renewalCredits: 0,
            issuerOrg: keccak256(abi.encodePacked(msg.sender)),
            credentialHash: credentialHash,
            revoked: false
        });
        
        emit CredentialIssued(
            holder,
            credentialType,
            msg.sender,
            block.timestamp + validityPeriod
        );
    }
    
    /**
     * @notice 更新資格
     */
    function renewCredential(
        address holder,
        bytes32 credentialType,
        uint256 additionalCredits
    ) external onlyAuthorizedIssuer {
        Credential storage cred = credentials[holder][credentialType];
        
        require(!cred.revoked, "Credential revoked");
        require(
            block.timestamp < cred.expiryDate,
            "Credential expired"
        );
        
        cred.renewalCredits += additionalCredits;
        cred.expiryDate += credentialTypes[credentialType].validityPeriod;
    }
    
    /**
     * @notice 撤銷資格
     */
    function revokeCredential(
        address holder,
        bytes32 credentialType,
        string calldata reason
    ) external onlyAuthorizedIssuer {
        Credential storage cred = credentials[holder][credentialType];
        
        require(!cred.revoked, "Already revoked");
        
        cred.revoked = true;
        
        emit CredentialRevoked(
            holder,
            credentialType,
            msg.sender,
            reason
        );
    }
    
    /**
     * @notice 驗證資格有效性
     */
    function verifyCredential(
        address holder,
        bytes32 credentialType
    ) external view returns (bool) {
        Credential storage cred = credentials[holder][credentialType];
        
        return 
            cred.issueDate > 0 &&
            !cred.revoked &&
            block.timestamp < cred.expiryDate;
    }
    
    modifier onlyAuthorizedIssuer() {
        require(
            authorizedIssuers[msg.sender],
            "Not an authorized issuer"
        );
        _;
    }
}

4.3 遊戲成就與社交

4.3.1 遊戲成就系統

/**
 * 遊戲成就 SBT 合約
 */
contract GameAchievementSBT is SoulboundToken {
    // 遊戲成就定義
    struct Achievement {
        bytes32 achievementId;
        string name;
        string description;
        uint256 rarity;      // 稀有度:1=Common, 2=Rare, 3=Epic, 4=Legendary
        uint256 pointValue; // 成就積分
        bytes32 prerequisite; // 前置成就
    }
    
    mapping(bytes32 => Achievement) public achievements;
    
    // 用戶成就記錄
    mapping(address => mapping(bytes32 => bool)) public userAchievements;
    mapping(address => uint256) public achievementPoints;
    
    // 遊戲管理器
    mapping(address => bool) public gameManagers;
    
    event AchievementUnlocked(
        address indexed player,
        bytes32 indexed achievementId,
        uint256 rarity
    );
    
    /**
     * @notice 註冊新成就類型
     */
    function registerAchievement(
        bytes32 achievementId,
        string calldata name,
        string calldata description,
        uint256 rarity,
        uint256 pointValue,
        bytes32 prerequisite
    ) external onlyOwner {
        achievements[achievementId] = Achievement({
            achievementId: achievementId,
            name: name,
            description: description,
            rarity: rarity,
            pointValue: pointValue,
            prerequisite: prerequisite
        });
    }
    
    /**
     * @notice 解鎖成就(由遊戲合約調用)
     */
    function unlockAchievement(
        address player,
        bytes32 achievementId
    ) external onlyGameManager {
        require(
            achievements[achievementId].achievementId == achievementId,
            "Achievement not registered"
        );
        require(
            !userAchievements[player][achievementId],
            "Already unlocked"
        );
        
        // 檢查前置成就
        Achievement memory ach = achievements[achievementId];
        if (ach.prerequisite != bytes32(0)) {
            require(
                userAchievements[player][ach.prerequisite],
                "Prerequisite not met"
            );
        }
        
        // Mint SBT
        uint256 tokenId = uint256(keccak256(abi.encodePacked(
            player,
            achievementId,
            block.timestamp
        )));
        
        mint(player, tokenId, _buildTokenURI(ach));
        
        // 更新記錄
        userAchievements[player][achievementId] = true;
        achievementPoints[player] += ach.pointValue;
        
        emit AchievementUnlocked(player, achievementId, ach.rarity);
    }
    
    /**
     * @notice 獲取玩家的成就統計
     */
    function getPlayerStats(address player) 
        external 
        view 
        returns (
            uint256 totalPoints,
            uint256 totalAchievements,
            uint256 commonCount,
            uint256 rareCount,
            uint256 epicCount,
            uint256 legendaryCount
        ) 
    {
        uint256[] memory tokens = tokensOf(player);
        
        totalAchievements = tokens.length;
        totalPoints = achievementPoints[player];
        
        for (uint256 i = 0; i < tokens.length; i++) {
            Achievement memory ach = achievements[tokens[i]];
            
            if (ach.rarity == 1) commonCount++;
            else if (ach.rarity == 2) rareCount++;
            else if (ach.rarity == 3) epicCount++;
            else if (ach.rarity == 4) legendaryCount++;
        }
    }
    
    function _buildTokenURI(
        Achievement memory ach
    ) internal pure returns (string memory) {
        return string(abi.encodePacked(
            "data:application/json,",
            '{"name":"', ach.name, '",',
            '"description":"', ach.description, '",',
            '"rarity":"', _rarityToString(ach.rarity), '",',
            '"points":"', Strings.toString(ach.pointValue), '"}'
        ));
    }
    
    function _rarityToString(uint256 rarity) 
        internal 
        pure 
        returns (string memory) 
    {
        if (rarity == 1) return "Common";
        if (rarity == 2) return "Rare";
        if (rarity == 3) return "Epic";
        return "Legendary";
    }
    
    modifier onlyGameManager() {
        require(gameManagers[msg.sender], "Not a game manager");
        _;
    }
}

第五章:隱私保護與監管合規

5.1 隱私保護機制

5.1.1 選擇性披露

SBT 的一個重要特點是支持選擇性披露——用戶可以證明自己持有某類 SBT,而不暴露具體是哪一個:

/**
 * 選擇性披露 SBT 系統
 * 使用零知識證明實現屬性驗證而不暴露具體 SBT
 */
contract SelectiveDisclosureSBT {
    // SBT 持有承諾
    mapping(address => bytes32) public commitment;
    mapping(bytes32 => bool) public commitmentUsed;
    
    // Merkle 樹根(代表所有有效 SBT)
    uint256 public currentRoot;
    mapping(uint256 => bool) public historicalRoots;
    
    // 零知識驗證器
    IZKVerifier public verifier;
    
    /**
     * @notice 創建披露承諾
     * @param sbtIds 持有的 SBT IDs
     * @param secret 用戶秘密值
     * @return bytes32 承諾哈希
     */
    function createCommitment(
        uint256[] memory sbtIds,
        uint256 secret
    ) public returns (bytes32) {
        // 計算承諾
        bytes32 hash = keccak256(abi.encodePacked(
            keccak256(abi.encodePacked(sbtIds)),
            secret
        ));
        
        commitment[msg.sender] = hash;
        commitmentUsed[hash] = false;
        
        return hash;
    }
    
    /**
     * @notice 生成選擇性披露證明
     * @param merkleProof Merkle 證明
     * @param secret 用戶秘密
     * @param disclosedAttributes 要披露的屬性
     * @return bytes32 承諾哈希
     */
    function proveOwnership(
        uint256[] calldata merkleProof,
        uint256 secret,
        uint256[] calldata disclosedAttributes
    ) external view returns (bytes32) {
        // 生成 ZK 證明
        bytes memory proof = verifier.generateProof(
            msg.sender,
            merkleProof,
            secret,
            disclosedAttributes
        );
        
        return commitment[msg.sender];
    }
    
    /**
     * @notice 驗證選擇性披露
     */
    function verifyDisclosure(
        uint256 root,
        bytes32 nullifierHash,
        uint256[] calldata disclosedAttributes,
        bytes calldata proof
    ) external view returns (bool) {
        require(
            historicalRoots[root],
            "Invalid root"
        );
        
        return verifier.verify(
            root,
            nullifierHash,
            disclosedAttributes,
            proof
        );
    }
}

5.2 監管合規框架

5.2.1 KYC/AML 合規整合

/**
 * 符合 KYC/AML 要求的身份合約
 */
contract KYCCompliantIdentity {
    // KYC 狀態
    enum KYCStatus { None, Pending, Verified, Suspended, Revoked }
    
    mapping(address => KYCStatus) public kycStatus;
    mapping(address => uint256) public kycExpiry;
    
    // 合規服務商
    address public complianceOracle;
    
    // 監管要求
    struct ComplianceRequirement {
        bool requireKYC;
        uint256 kycExpiryDays;
        bool requireAccreditedInvestor;
        bool requireAMLCheck;
    }
    
    mapping(address => ComplianceRequirement) public requirements;
    
    /**
     * @notice 請求 KYC 驗證
     */
    function requestKYC(
        bytes calldata kycData
    ) external {
        require(
            kycStatus[msg.sender] == KYCStatus.None,
            "KYC already requested"
        );
        
        kycStatus[msg.sender] = KYCStatus.Pending;
        
        // 發送 KYC 資料到合規服務商
        IComplianceOracle(complianceOracle).submitKYCRequest(
            msg.sender,
            kycData
        );
    }
    
    /**
     * @notice 合規服務商回調(驗證 KYC 結果)
     */
    function completeKYC(
        address user,
        KYCStatus status,
        uint256 expiryDays
    ) external onlyComplianceOracle {
        kycStatus[user] = status;
        kycExpiry[user] = block.timestamp + (expiryDays * 1 days);
    }
    
    /**
     * @notice 檢查用戶是否滿足合規要求
     */
    function checkCompliance(
        address user,
        address serviceProvider
    ) external view returns (bool) {
        ComplianceRequirement memory req = requirements[serviceProvider];
        
        if (req.requireKYC) {
            if (kycStatus[user] != KYCStatus.Verified) {
                return false;
            }
            if (block.timestamp > kycExpiry[user]) {
                return false;
            }
        }
        
        if (req.requireAMLCheck) {
            if (!_checkAMLStatus(user)) {
                return false;
            }
        }
        
        return true;
    }
    
    function _checkAMLStatus(address user) internal view returns (bool) {
        return IComplianceOracle(complianceOracle).checkAMLStatus(user);
    }
    
    modifier onlyComplianceOracle() {
        require(
            msg.sender == complianceOracle,
            "Not compliance oracle"
        );
        _;
    }
}

結論

Soulbound Token 和去中心化身份技術正在以太坊生態系統中迅速發展,從 DAO 治理到專業認證,從遊戲成就到社交網路,SBT 的應用場景日益豐富。

核心要點回顧

維度關鍵洞察
技術標準ERC-5192 提供了 SBT 的最小標準,平衡了不可轉讓性與靈活性
身份系統ENS 和 World ID 分別從域名和生物特徵兩個維度構建身份基礎
應用場景DAO 治理、專業認證、遊戲成就是最成熟的三大應用方向
隱私保護零知識證明實現選擇性披露,保護用戶隱私
監管合規KYC/AML 合規框架正在與 DID 系統整合

未來發展方向

隨著技術成熟和監管明確化,SBT 和 DID 將在以下領域持續演進:

去中心化身份代表了區塊鏈技術在信任建立方面的核心創新,SBT 作為其代幣化表現,將在 Web3 的身份系統建設中發揮關鍵作用。


參考文獻

技術規範

  1. Buterin, V., et al. (2022). "Soulbound." Ethereum Research. https://ethresear.ch
  2. W3C. (2022). "Decentralized Identifiers (DIDs) v1.0." https://www.w3.org/TR/did-core/
  3. W3C. (2022). "Verifiable Credentials Data Model 1.1." https://www.w3.org/TR/vc-data-model/
  4. Ethereum Foundation. (2023). "ERC-5192: Soul Bound Token." https://eips.ethereum.org/EIPS/eip-5192

實現與項目

  1. ENS. (2026). "Ethereum Name Service Documentation." https://docs.ens.domains
  2. Worldcoin. (2026). "World ID Technical Documentation." https://docs.worldcoin.org
  3. Semaphore. (2024). "Semaphore: A Zero-Knowledge Protocol for Anonymous Identity." https://semaphore.appliedzkp.org

學術論文

  1. Dunphy, P., & Petitcolas, F. A. (2018). "A First Look at Identity Management Schemes on the Blockchain." IEEE Security & Privacy.
  2. Tobin, A., & Reed, D. (2016). "The Inevitable Rise of Self-Sovereign Identity." Sovrin Foundation.

監管資料

  1. European Union. (2024). "eIDAS 2.0 Regulation." https://digital-strategy.ec.europa.eu
  2. FATF. (2024). "Guidance for a Risk-Based Approach to Virtual Asset Service Providers."

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!