JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

權利金、靈魂綁定代幣與帳戶抽象化(ERC-4337)

代幣標準的三片前沿——它們不再只談「誰擁有什麼」,而是開始改寫規則:試圖永遠跟著作品走的金錢、拒絕被賣掉的所有權,以及變身為可程式化智慧合約的錢包。

走出「誰擁有它」

一位插畫家鑄造了一件作品,以 1 ETH 賣出,並在上架資訊裡寫上「10% 權利金」。一年後同一張圖以 80 ETH 轉手。她從這筆暴利分到多少?常常是零。不是因為有人駭了她的合約——而是因為在多數鏈上,權利金是一種禮貌性的請求,而非協定會強制執行的規則。

這一階前面的指南教過你代幣是什麼ERC-20 的餘額、ERC-721 NFT 那獨一無二的 tokenId、ERC-1155 的多代幣效率,以及一個 NFT 的圖片究竟存在哪裡。這些標準都在回答同一個問題——誰擁有什麼,又如何轉移? 這最後一篇談的是三片改寫這個問題的前沿:試圖永遠跟著代幣走的金錢(EIP-2981 權利金)、根本拒絕轉移的所有權(靈魂綁定代幣),以及錢包本身變成你能程式化的智慧合約ERC-4337 帳戶抽象化)。

EIP-2981:鏈能描述、卻無法強制的權利金

EIP-2981 刻意做得極小。它只新增一個唯讀函式 `royaltyInfo`,輸入一筆售價,回答兩件事:該付給、以及付多少。就這樣。它不搬動任何金錢、不碰任何餘額——它只是一張市集可以讀取的標籤。

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

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {IERC2981} from "@openzeppelin/contracts/interfaces/IERC2981.sol";

contract ArtNFT is ERC721, IERC2981 {
    address public royaltyReceiver;
    uint96  public royaltyBps;          // basis points: 500 = 5%

    constructor(address receiver, uint96 bps) ERC721("ArtNFT", "ART") {
        royaltyReceiver = receiver;
        royaltyBps      = bps;          // e.g. 500 for 5%
    }

    // EIP-2981: given a sale price, report who is owed how much.
    // NOTE: this only *reports*. It never receives or forwards funds.
    function royaltyInfo(uint256 /*tokenId*/, uint256 salePrice)
        external view returns (address receiver, uint256 royaltyAmount)
    {
        return (royaltyReceiver, (salePrice * royaltyBps) / 10_000);
    }

    // Tell the world (and marketplaces) we implement the standard.
    function supportsInterface(bytes4 id) public view override returns (bool) {
        return id == type(IERC2981).interfaceId || super.supportsInterface(id);
    }
}
一個最精簡的 EIP-2981 NFT。權利金以基點報價(10,000 = 100%),所以 10 ETH 售價、500 基點,就是 (10 × 500) / 10,000 = 0.5 ETH 歸創作者。

這裡有個界定整個主題的關鍵:`royaltyInfo` 是個 view 函式。當買家轉移一個 NFT 時,ERC-721 標準裡沒有任何東西會去呼叫它。是市集合約必須選擇去讀那個數字、拆分款項、把該給的份額送給創作者。如果它不做,轉移照樣成功,創作者卻一毛都拿不到。權利金是鏈上真實存在的資料,卻附著在一筆可能永遠不會照藝術家所願發生的交易上。

這並非假設。2022–2023 年間上演了一場「權利金戰爭」:像 Blur 這樣的交易場所以「創作者費用可選」為競爭手段,許多系列的實際權利金支付一路崩向零。OpenSea 以一套 Operator Filter Registry(運營者過濾登錄) 反擊,封鎖向不尊重權利金之市集的轉移——然後在 2024 年 8 月,當整個生態系不滿這種強硬作風時,悄悄將其棄用。如今真心想要強制執行的專案,會轉向像 Limit Break 的 ERC-721-C 這類設計:讓每一次轉移都通過一個鏈上驗證器把關,而那個驗證器可以要求權利金必須付清。

靈魂綁定代幣:賣不掉的所有權

現在把問題反過來。權利金之所以棘手,是因為轉移太自由。那如果轉移正是你想要的呢?一張大學文憑、一枚「完成此課程」徽章、一張出席證明、一段信用紀錄——這些只有黏在身上才有意義。一張能向陌生人買來的文憑毫無價值。這正是靈魂綁定代幣(SBT)的構想:綁定在單一帳戶上、不可轉讓的代幣。

這個詞出自 Vitalik Buterin(2022 年 1 月的一篇部落格文章,借用了《魔獸世界》的用語),並在 2022 年 5 月的論文《Decentralized Society: Finding Web3's Soul(去中心化社會:尋找 Web3 的靈魂)》中加以延伸。關鍵在於:你不需要一個全新的標準就能做出一個——你拿一個普通的 ERC-721,再移除轉移的能力即可。在 OpenZeppelin v5 合約裡,鑄造、轉移與銷毀全都匯流到單一的內部掛鉤 `_update`,所以一次覆寫就能把代幣封死:

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

import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";

/// A credential that can be MINTED to a wallet and BURNED by it,
/// but never TRANSFERRED to another wallet.
contract Credential is ERC721 {
    error TokenIsSoulbound();

    // EIP-5192: a minimal interface so wallets/marketplaces know it's locked.
    event Locked(uint256 tokenId);

    constructor() ERC721("Credential", "CRED") {}

    function locked(uint256) external pure returns (bool) {
        return true; // always locked
    }

    // In OZ v5, mint/transfer/burn all route through _update.
    //   from == 0  -> mint   (allowed)
    //   to   == 0  -> burn   (allowed: you may give it up)
    //   otherwise  -> transfer (blocked)
    function _update(address to, uint256 tokenId, address auth)
        internal override returns (address)
    {
        address from = _ownerOf(tokenId);
        if (from != address(0) && to != address(0)) revert TokenIsSoulbound();
        return super._update(to, tokenId, auth);
    }
}
一個靈魂綁定的憑證。EIP-5192 只標準化了 locked()/Locked/Unlocked,讓工具能偵測不可轉讓性;我們仍允許鑄造(發放)與銷毀(持有者放棄它)。

真實的用途已經出現:POAP(你出席過某活動的證明)、鏈上憑證與 KYC 認證、類似 Gitcoin Passport 的信譽,以及代幣門禁式的存取——而這把「鑰匙」沒辦法直接賣給黃牛。SBT 也暗示了今日 DeFi 做不到的一件事——低抵押借貸:用一段不可轉讓的信用信譽(而不只是鎖住的資本)來為貸款背書。

帳戶抽象化:當錢包變成智慧合約

每一個一般的 以太坊錢包——你 MetaMask 種子片語背後的那個——都是外部擁有帳戶(EOA)。它只有一條硬寫死的規則:一筆交易要有效,必須帶有來自單一私鑰的一個 ECDSA 簽章。那把唯一的金鑰就是你的全部身分。弄丟它,錢就永遠沒了。沒有「忘記密碼」、沒有消費上限、沒有「需要我三把金鑰中的兩把」,而且你永遠得自己持有 ETH 來付 gas。簽章規則被烙進了協定裡;你改不了它。

帳戶抽象化問的是:如果「這筆交易有效嗎?」的規則本身,是一段由你撰寫的程式碼呢?ERC-4337 正好實現了這件事——而最巧妙的地方在於,它做到這點完全不必更動以太坊的共識。它不去碰協定,而是在協定之上、用智慧合約搭起一套平行的交易系統。你的錢包變成一個智慧帳戶:一個自己決定「什麼才算有效動作」的合約。

讓這套機制運轉的,有四個零件:

  1. UserOperation(使用者操作)——不是一筆普通交易,而是一個描述你的智慧帳戶想做什麼的偽交易物件。你用帳戶自選的方式簽署它(一把金鑰、多簽、一把 passkey……),再把它丟進一個獨立的「替代記憶池」。
  2. Bundler(打包者)——一個角色(很像區塊建構者),它盯著替代記憶池、蒐集許多 UserOperation,把它們包進一筆普通的鏈上交易。打包者先墊付 gas,事後再獲得補償。
  3. EntryPoint(進入點合約)——一個經過稽核、所有智慧帳戶都信任的單例合約。它分兩階段(先驗證、再執行)跑每個 UserOperation,並負責把錢補償給打包者,這樣個別帳戶就不必自己處理。
  4. Paymaster(代付者)——一個選用的合約,它同意為你的操作支付 gas:它可以完全贊助使用者(無 gas 入門),或讓他們改用像 USDC 這樣的 ERC-20 來付費,而非用 ETH。

拆開一個 UserOperation

一個 UserOperation 像是交易那位野心勃勃的表親。它帶著一般的 gas 與 nonce 欄位,但有兩樣東西特別突出:一個能在首次使用時部署帳戶的 `initCode`(透過 CREATE2,所以位址在合約存在之前就已知道——所謂「反事實」部署),以及一個協定從不檢查的 `signature`。取而代之,是由你帳戶自己的程式碼來驗證它。

// The pseudo-transaction a smart account signs (ERC-4337 v0.6).
struct UserOperation {
    address sender;               // the smart account itself
    uint256 nonce;                // replay protection (per-account)
    bytes   initCode;             // deploys the account on first use (CREATE2)
    bytes   callData;             // what the account should actually do
    uint256 callGasLimit;
    uint256 verificationGasLimit;
    uint256 preVerificationGas;
    uint256 maxFeePerGas;
    uint256 maxPriorityFeePerGas;
    bytes   paymasterAndData;     // optional sponsor (paymaster) + its data
    bytes   signature;            // checked by the ACCOUNT, not the protocol
}

// During the verification phase the EntryPoint calls this on your account.
// Return 0 to accept; this is where you put YOUR rules.
interface IAccount {
    function validateUserOp(
        UserOperation calldata userOp,
        bytes32 userOpHash,
        uint256 missingAccountFunds   // top-up the account owes the EntryPoint
    ) external returns (uint256 validationData);
}
ERC-4337 v0.6 的結構。因為 validateUserOp 是你的程式碼,「有效」可以指一個 passkey 簽章、2-of-3 多簽、每日消費上限,或一把 session 金鑰——任何你能用 Solidity 表達的規則。

EntryPoint 以兩個嚴格的迴圈處理一個批次。首先是驗證迴圈:對每個操作呼叫 `validateUserOp`,依你的自訂規則檢查簽章與 nonce,並向 EntryPoint 預付一筆 gas。只有當每個操作都通過後,執行迴圈才會去跑每個操作的 `callData`。把驗證與執行拆開,正是讓打包者能安全地把陌生人的操作批在一起的關鍵:一個壞簽章在第一階段就被免費駁回,不會進到第二階段那些昂貴的工作。

帳戶抽象化解鎖了什麼——又付出什麼代價

一旦「有效」變得可程式化,那些長年的錢包痛點就變成你能交付的功能:

  1. Gas 贊助——由代付者支付 gas,讓新使用者在身上一點 ETH 都沒有的情況下就能簽出第一個動作,或用 USDC 付費。入門不再需要先跑去交易所,只為了買「付 gas 的錢」。
  2. 社交復原——指定一群守護者(朋友、裝置、某個機構),在你弄丟金鑰時由他們一起替你輪換簽章金鑰。一個社交復原錢包把「弄丟種子片語=永遠失去資金」變成一件可以挺過去的事。
  3. 批次處理與 session 金鑰——一鍵完成「先批准、再兌換」,而非兩筆交易;或授予一款遊戲一把受限的「session 金鑰」,讓它在一小時內做些小額操作,而不必為每一步重新簽名。
  4. 自訂簽章——驗證手機的 passkey(secp256r1)而非種子片語,讓錢包用起來像 Face ID,而不是 24 個嚇人的單字。

這一切都不是免費的。智慧帳戶比 EOA 耗更多 gas(每個操作都多了額外的合約呼叫),替代記憶池/打包者這套基礎設施比以太坊基礎層更年輕、也更中心化,而代付者是一個你得仰賴它持續贊助的受信任方——而且若它贊助得不謹慎,還會成為被惡意消耗的目標。再加上 EOA 至今仍是絕大多數的錢包,所以 dApp 在未來數年內都得同時支援這兩個世界。

把這片前沿串起來

退一步看,這三片前沿彼此押韻。權利金想讓金錢跟著一個能自由流動的代幣走,卻發現沒有強制執行,標準就只能「建議」。靈魂綁定代幣想讓一個代幣永遠不移動,卻發現把它釘在單一位址上,會生出新的隱私與復原問題。而帳戶抽象化回答了復原問題——還不只如此——靠的是讓帳戶本身可程式化,於是錢包不再是一把脆弱的單一金鑰,而成為一份帶著規則的合約。

這也是整個這一階的主軸:一個代幣標準從來不只是一種資料格式——它是一份微型社會契約,規範著錢包、市集與其他合約可以對彼此做出哪些假設。從這裡開始,階梯轉向這些代幣在何處大規模地生存與交易:你現在已會撰寫的這些合約,正是後面的安全、DeFi 與擴容各階將要壓力測試、攻擊與優化的對象。