newsence

ERC-8191:鏈上定期循環支付標準

Ethereum Magicians·26 天前

本提案介紹了 ERC-8191,這是一個針對以太坊及 EVM 相容鏈的 Solidity 標準介面,旨在透過守護者閘控的拉取支付模型,實現去信任化且自動化的鏈上定期循環支付。

摘要

本提案定義了一個標準的 Solidity 介面 —— ISubscription —— 用於以太坊及 EVM 相容鏈上的鏈上定期付款。它引入了一種拉取式付款(pull-payment)模型,具備完整的訂閱生命週期管理(創建、暫停、恢復、取消)、守護者門控(keeper-gated)的付款收集、原生 ETH 與 ERC-20 支援,以及為商家提供的選用回調介面。目前已提供測試覆蓋率 >95% 的參考實現。


動機

定期付款是數位經濟的基礎原語。儘管如此,目前尚不存在一個已定稿的 ERC 標準來實現去信任化、自動化的鏈上訂閱。

先前的兩次嘗試均未成功:

ERC-1337 (2018):需要鏈下元交易(meta-transaction)中繼者,引入了中心化與信任假設。從未編寫過測試套件。目前處於停滯狀態。

ERC-5643:僅限於基於 NFT 的會員資格。缺乏拉取式付款機制,沒有狀態管理(暫停、寬限期、重試)。這只是大問題的局部解決方案。

其結果是,現今每個構建定期付款的協議都在重新發明自己的邏輯 —— 這些邏輯不具備組合性,無法通過共享標準進行審計,且與任何共享工具層都不相容。

本提案旨在永久解決這一問題。


規範

核心類型

struct SubscriptionTerms {
    address token;        // ERC-20 地址,原生 ETH 則為 address(0)
    uint256 amount;       // 每個週期的付款金額
    uint48  interval;     // 兩次付款之間的秒數
    uint48  trialPeriod;  // 首次付款前的免費試用秒數;0 = 無
    uint256 maxPayments;  // 最大付款次數;0 = 無限制
    uint256 originChainId;
    uint256 paymentChainId;
}

enum Status { Active, Paused, Cancelled, Expired, PastDue }

介面

interface ISubscription {
    function subscribe(address merchant, SubscriptionTerms calldata terms)
        external returns (bytes32 subId);

    function collectPayment(bytes32 subId) external returns (bool);

    function cancelSubscription(bytes32 subId) external;
    function pauseSubscription(bytes32 subId) external;
    function resumeSubscription(bytes32 subId) external;

    function getStatus(bytes32 subId) external view returns (Status);
    function nextPaymentDue(bytes32 subId) external view returns (uint256);
    function getTerms(bytes32 subId) external view returns (SubscriptionTerms memory);
    function getSubscriber(bytes32 subId) external view returns (address);
    function getMerchant(bytes32 subId) external view returns (address);
    function getPaymentCount(bytes32 subId) external view returns (uint256);
}

關鍵設計決策

collectPayment() 由守護者(keeper)門控。 訂閱者直接拉取(推播模型)無法實現自動化。而無限制的收集則會引入騷擾(griefing)風險。雙層 KeeperRegistry(由所有者設置的全域守護者 + 商家自我管理的專屬守護者)在去中心化與活性(liveness)之間取得了平衡。

PastDue(逾期)是在 getStatus() 中動態計算的。 這避免了單純為了更新狀態而需要守護者發送交易 —— 任何 view 調用都能反映正確的狀態。

bytes32 訂閱 ID 的推導方式為 keccak256(subscriber, merchant, block.timestamp, block.chainid, nonce) —— 具有確定性、跨鏈可移植性,且無需順序計數器即可防止碰撞。

address(0) 代表原生 ETH —— 與廣泛的慣例一致(例如 Uniswap, 1inch)。採用託管模式分離訂閱者與商家的 ETH 餘額,以消除重入攻擊向量。

使用 uint48 表示 interval 和 trialPeriod —— 可與其他結構體欄位共用同一個存儲插槽,支援長達約 890 萬年(對於任何實際用例而言實際上是無限的)。

選用擴展

以下擴展介面設計為可組合且透過 ERC-165 選擇性加入,遵循 ERC-721/ERC-721Enumerable 的先例:

ISubscriptionTrial —— 運行時試用查詢(isInTrial(), trialEndsAt(), extendTrial())

ISubscriptionTiered —— 分級定價(Tier 結構體, createTier(), upgradeTier(), downgradeTier())

ISubscriptionDiscovery —— 帶有鏈下元數據 URI 的極簡鏈上商家註冊表

ISubscriptionHook —— 針對付款失敗的催款(dunning)回調(由鏈下自動化調用,而非由 SubscriptionManager 調用)

選用商家回調

interface ISubscriptionReceiver {
    function onPaymentCollected(bytes32 subId, uint256 amount, address token)
        external returns (bytes4);
    function onSubscriptionCancelled(bytes32 subId)
        external returns (bytes4);
}

商家透過實現此介面並返回函數選擇器(function selector)來選擇加入。在參考實現中,回調被封裝在 try/catch 中 —— 商家回調的 revert 永遠不會阻礙付款收集。


向後相容性

此 ERC 引入了一個新介面,不修改也不與任何現有標準衝突。它與 ERC-20、ERC-165 和 ERC-7683(跨鏈意圖)相容。ERC-5643 的實現不需要遷移;本標準可以與之共存。


參考實現

完整的 Foundry 參考實現可在以下網址取得:github.com/cadence-protocol/cadence-protocol

src/interfaces/ISubscription.sol — 完整介面

src/SubscriptionManager.sol — 參考實現(ERC-20 + ETH, 託管, 試用, 守護者門控, 接收者回調)

src/KeeperRegistry.sol — 帶有黑名單的雙層守護者授權

test/ — 90 多個單元測試、模糊測試和不變量測試(分支覆蓋率 >95%)

docs/rationale.md — 針對上述所有決策的詳細設計原由


社群提問

collectPayment() 訪問模型:KeeperRegistry 是正確的抽象嗎?還是應該完全交由實現者決定,不在介面中設置鏈上門控?

跨鏈:SubscriptionTerms 中的 originChainId / paymentChainId 預見了 ERC-7683 意圖。將其編碼在結構體中是正確的方法嗎?還是跨鏈應該作為一個獨立的擴展?

PastDue 作為計算狀態:對於不存儲在狀態中的狀態值是否有任何異議?

擴展介面粒度:四個擴展介面(試用、分級、發現、鉤子)的劃分是否合適?還是應該合併其中一些?

期待聽到任何感興趣的人的反饋。

Cadence Protocol 團隊

[更新] 正式的 ERC 草案已提交:https://github.com/ethereum/ERCs/pull/1595

        1 則貼文 - 1 位參與者

        [閱讀完整主題](https://ethereum-magicians.org/t/erc-8191-onchain-recurring-payments/27946)
https://ethereum-magicians.org/t/erc-8191-onchain-recurring-payments/27946