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 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 驗證
- 監管框架整合:符合全球各地監管要求的標準
- 與 AI 整合:AI 代理的身份驗證與授權
去中心化身份代表了區塊鏈技術在信任建立方面的核心創新,SBT 作為其代幣化表現,將在 Web3 的身份系統建設中發揮關鍵作用。
參考文獻
技術規範
- Buterin, V., et al. (2022). "Soulbound." Ethereum Research. https://ethresear.ch
- W3C. (2022). "Decentralized Identifiers (DIDs) v1.0." https://www.w3.org/TR/did-core/
- W3C. (2022). "Verifiable Credentials Data Model 1.1." https://www.w3.org/TR/vc-data-model/
- Ethereum Foundation. (2023). "ERC-5192: Soul Bound Token." https://eips.ethereum.org/EIPS/eip-5192
實現與項目
- ENS. (2026). "Ethereum Name Service Documentation." https://docs.ens.domains
- Worldcoin. (2026). "World ID Technical Documentation." https://docs.worldcoin.org
- Semaphore. (2024). "Semaphore: A Zero-Knowledge Protocol for Anonymous Identity." https://semaphore.appliedzkp.org
學術論文
- Dunphy, P., & Petitcolas, F. A. (2018). "A First Look at Identity Management Schemes on the Blockchain." IEEE Security & Privacy.
- Tobin, A., & Reed, D. (2016). "The Inevitable Rise of Self-Sovereign Identity." Sovrin Foundation.
監管資料
- European Union. (2024). "eIDAS 2.0 Regulation." https://digital-strategy.ec.europa.eu
- FATF. (2024). "Guidance for a Risk-Based Approach to Virtual Asset Service Providers."
相關文章
- 去中心化身份與 ENS 完整指南:域名服務、身份驗證與應用場景 — 去中心化身份(Decentralized Identity,簡稱 DID)是區塊鏈領域近年來快速發展的重要賽道。傳統網路身份仰賴中心化機構發放的帳戶,帶來了隱私洩露、帳戶被刪除、跨平台身份割裂等問題。去中心化身份旨在將身份的所有權歸還給用戶,透過區塊鏈技術實現可驗證、可攜帶、、抗審查的身份系統。
- 以太坊新興應用場景深度分析:供應鏈追蹤、數位身份、遊戲Fi的技術架構與實踐案例 — 本文深入分析以太坊在供應鏈管理、數位身份和遊戲Fi三大新興應用場景的技術架構、主要項目與實際案例。涵蓋從 IBM Food Trust 到 WineChain 的供應鏈溯源解決方案,從 ENS 到 Polygon ID 的去中心化身份系統,從 Axie Infinity 到 The Sandbox 的區塊鏈遊戲生態,並探討 Layer 2、NFT 標準、零知識證明等技術在這些領域的應用與未來發展趨勢。
- 以太坊治理完整指南:從基金會運作到社區決策機制 — 本文深入探討以太坊治理的各個面向,從以太坊基金會的角色定位出發,詳細解析EIP(以太坊改進提案)的完整流程與實際案例,分析Gov DAO的運作模式,並探討治理過程中面臨的挑戰與未來發展方向。我們將涵蓋技術治理、經濟治理和生態治理三個層次,幫助讀者全面理解這個複雜而精密的去中心化決策系統。
- AI + Web3 理財報自動化管理完整技術指南:以太坊智能合約與人工智慧整合實踐 — 傳統企業財務報表的編製過程耗時費力,涉及大量的手動資料彙總、驗證和對帳工作。隨著區塊鏈技術與人工智慧的快速發展,一種全新的財務報管理範式正在興起——透過將企業資源規劃(ERP)系統與以太坊智慧合約深度整合,結合 AI 驅動的資料處理與分析能力,實現理財报的自動化編製、即時驗證和不可篡改的歷史存證。本文深入探討這項技術整合的架構設計、實施細節與實際應用案例。
- 以太坊與高性能區塊鏈系統性比較分析:Monad、Sui、Aptos 架構深度比較與生態系統全景 — 本文從工程師視角對以太坊與 Monad、Sui、Aptos 等高性能區塊鏈進行系統性的技術比較分析,深入探討各平台的核心設計理念、效能表現、優劣勢以及未來發展趨勢。我們涵蓋共識層、執行層、儲存層、網路層等多個技術維度,同時分析各鏈的生態系統發展狀況和實際應用場景,為開發者和投資者提供全面的技術決策參考截至 2026 年第一季度。
延伸閱讀與來源
- 以太坊基金會生態系統頁面 官方認可的生態項目列表
- The Graph 去中心化索引協議
- Chainlink 文檔 預言機網路技術規格
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!