ERC-4885: 订阅 NFT 和多代币
一种订阅代币的接口,让持有者可以订阅 NFT 和多代币
Authors | Jules Lai (@julesl23) |
---|---|
Created | 2022-03-08 |
Discussion Link | https://ethereum-magicians.org/t/eip-subscription-token-standard/8531 |
Requires | EIP-165, EIP-721, EIP-1155 |
Table of Contents
摘要
以下标准允许为订阅非同质化代币和多代币实现标准 API。EIP-20 代币被存入,以换取订阅代币,这些代币赋予在指定的时间限制或无限期内使用所述非同质化代币和多代币的权利。
动机
此标准提供了一种灵活、通用的方式来订阅 EIP-721 或 EIP-1155 合约提供的资产或服务。从现在开始,为了简单起见,这些合约将被称为 NFT;提供者是所述 NFT 的发行者,订阅者使用它们。
这个提案最初的想法是让音乐和电影的创作者重新获得控制权。数字内容的分发和交付目前是中心化的科技公司的职权范围,他们向客户提供同质化的订阅模式。这个提案指定了一种标准,供 dapp 开发者使用,使创作者能够设置自己的自定义订阅模式,从而开辟新的收入来源,从而实现去中心化的分发和交付模式。
用例包括任何类型的定期(例如,每日、每周、每月、每季度、每年/年度或季节性)使用或访问资产或服务,例如:
- 流媒体音乐、视频、电子学习或书籍/新闻服务的订阅
- 订阅者之间共享数字资产
- 俱乐部会员资格,如健身俱乐部
- 体育和电子竞技的季票
- 双方之间达成协议,在 DeFi 中交换固定利率订阅流和可变收入
- 租赁游戏内资产
- 等等
订阅代币借鉴了 EIP-20 规范中的一些函数。实施者可以自由地实现标准的其余部分;例如,允许订阅代币在二级市场上交易、作为礼物发送或用于退款等。
规范
订阅者存入 EIP-20 以接收 NFT 和订阅。订阅代币余额在使用 NFT 的生命周期内自动线性减少,并且一旦订阅代币余额降至零,则 NFT 的使用将被禁用。订阅者可以通过存入 EIP-20 代币来换取更多的订阅代币来增加余额,从而延长订阅的生命周期。
实现此 EIP 标准的智能合约必须实现 EIP-165 的 supportsInterface 函数,并且如果通过 interfaceID 参数传递 0xC1A48422,则必须返回常量值 true。请注意,本文档中的 revert 可能表示具有或不具有错误消息的 require、throw(不推荐使用,因为它已弃用)或 revert solidity 语句。
interface ISubscriptionToken {
/**
@dev 当订阅代币构造函数或初始化方法被执行时,会发出此事件。
@param name 订阅代币的名称
@param symbol 订阅代币的符号
@param provider 接收存款的提供者
@param subscriptionToken 订阅代币合约地址
@param baseToken 用于存款的 ERC-20 兼容代币。
@param nft 提供者从中铸造/转移的 `nft` 的地址。
此接口中引用的所有 tokenIds 必须是此 `nft` 合约的代币实例。
*/
event InitializeSubscriptionToken(
string name,
string symbol,
address provider,
address indexed subscriptionToken,
address indexed baseToken,
address indexed nft,
string uri
);
/**
@dev 这会为 token `tokenId` 的 `nft` 合约的每个新订阅者发出。
`subscriber` 必须在其帐户中收到 token `tokenId` 的 `nft`。
@param subscriber 订阅者帐户
@param tokenId 必须是发送给 `subscriber` 的 `nft` 的代币 id
@param uri 必须是发送给 `subscriber` 的 `nft` 的 uri 或空字符串
*/
event SubscribeToNFT(
address indexed subscriber,
uint256 indexed tokenId,
string uri
);
/**
@dev 当 `subscriber` 通过 `deposit` 方法存入 token 类型为 `baseToken` 的 ERC-20 时发出。
这会增加 `subscriber` 的订阅代币余额
@param depositAmount 存入的 `baseToken` 类型的 ERC-20 金额
@param subscriptionTokenAmount 发送给 `subscriber` 以换取的订阅代币金额
@param subscriptionPeriod 订阅延长的额外时间量,以秒为单位
*/
event Deposit(
address indexed subscriber,
uint256 indexed tokenId,
uint256 depositAmount,
uint256 subscriptionTokenAmount,
uint256 subscriptionPeriod
);
/**
@return 订阅代币的名称
*/
function name() external view returns (string memory);
/**
@return 订阅代币的符号
*/
function symbol() external view returns (string memory);
/**
@notice 将 `subscriber` 订阅到 'tokenId' 的 `nft`。`subscriber` 必须在他们的帐户中收到代币 `tokenId` 的 `nft`。
@dev 如果 `subscriber` 已经订阅了 'tokenId' 的 `nft`,则必须 revert
如果 'nft' 尚未批准 `subscriptionToken` 合约地址作为运营商,则必须 revert。
@param subscriber 订阅者帐户。如果为零地址,则必须 revert。
@param tokenId 必须是发送给 `subscriber` 的 `nft` 合约的代币 id
从事件 `SubscribeToNFT` 发出的 `tokenId` 必须与 tokenId 相同,除非
tokenId 为零;允许 OPTIONAL 的 tokenid,然后由 `nft` 合约在内部设置和铸造
@param uri `nft` 的 OPTIONAL uri。
从事件 `SubscribeToNFT` 发出的 `uri` 必须与 uri 相同,除非 uri 为空。
*/
function subscribeToNFT(
address subscriber,
uint256 tokenId,
string memory uri
) external;
/**
@notice 增加 `subscriber` 持有的订阅代币的余额
@dev 如果 `subscriber` 未订阅 'tokenId' 的 `nft`,则必须 revert
如果 'nft' 尚未批准 `subscriptionToken` 合约地址作为运营商,则必须 revert。
@param subscriber 订阅者帐户。如果为零地址,则必须 revert。
@param tokenId 要订阅的 `nft` 合约的代币 id
@param depositAmount 要存入的合约地址 `baseToken` 的 ERC-20 代币金额
以换取合约地址 `subscriptionToken` 的订阅代币
*/
function deposit(
address subscriber,
uint256 tokenId,
uint256 depositAmount
) external payable;
/**
@return `subscriber` 持有的订阅代币的余额。
建议对于有时限的订阅,余额线性减少到零
建议对于终身订阅,余额保持不变
如果 `subscriber` 不持有 'tokenId' 的 `nft`,则必须返回零余额
如果订阅尚未通过 `deposit` 函数开始,则必须 revert
当余额为零时,`subscriber` 必须不允许使用 `tokenId` 的 `nft`
*/
function balanceOf(address subscriber) external view returns (uint256);
}
订阅代币余额
一个示例实现铸造一定数量的订阅代币,总计为订阅者支付的订阅期长度的每天一个订阅代币;例如,一周将是七个订阅代币。然后,订阅代币余额每天以每个代币的速度连续且线性地自动减少,直到为零。balanceOf
函数可以通过仅在作为 view 函数调用时计算剩余的订阅代币数量来懒惰地实现,因此没有 gas 成本。
订阅代币价格
每代币每秒支付的订阅代币价格可以从 Deposit
事件参数计算得出,如下所示:
depositAmount
/ (subscriptionTokenAmount
* subscriptionPeriod
)
NFT 元数据
NFT 的元数据可以存储提供者在订阅期间提供给订阅者的资产/服务的信息。这可能是提供者提供给订阅者的约定的订阅服务的条款和条件。如果直接提供 NFT 资产,则它也可能是 NFT 资产的元数据。此标准有意保持通用性,以适应 NFT 的许多不同用例。
订阅到期
当订阅者的订阅代币余额降至零时(表示订阅已过期),则由实施者决定如何针对其特定用例处理此问题。例如,提供者可能会停止向订阅者流式传输媒体服务。对于代表链下存储的图像的 NFT,也许 NFT 的 uri
函数不再返回其元数据的链接。
注意事项
对于一些基于法定货币的传统订阅模型,订阅者保存的支付凭据用于在到期时或到期前自动购买以延长订阅期。此功能在此提案规范中是不可能的,因为在使用纯加密货币时,每次支付都必须获得订阅者签名批准的许可才能进行定期支付。
此提案不直接处理暂停订阅,实施者可以编写自己的或继承自第三方智能合约抽象,例如 OpenZeppelin 的 Pausable。在这种情况下,balanceOf
方法将需要额外的逻辑和存储来计算订阅代币暂停的时间长度。
理由
订阅代币化
订阅本身在交换押金时具有价值。此提案使订阅能够“代币化”,因此可以存在二级市场,可以在其中买卖订阅代币。例如,粉丝可能想将他们的季票(可以访问现场体育赛事)卖给另一位粉丝。如果仅向 NFT 添加了日期到期扩展功能,则这将不会那么容易实现。 实施者可以简单地实现 EIP-20 的其余功能,以便交易订阅代币。是否提供提供的订阅服务是非同质化的还是同质化的,由实施者决定。如果非同质化,那么购买订阅代币将仅仅给出相同的剩余到期时间。如果同质化,并且购买者已经拥有相同服务的现有订阅,那么他们的总订阅期可以按照购买的订阅代币的数量进行延长。
满足当前和未来 NFT 的使用
此提案特意在 subcribeToNFT
方法中保留 tokenId
和 uri
可选,以保持规范的通用性。某些用例(例如预先计算的图像 NFT 集合)不需要不同的“uri”,只需要每个 NFT 不同的 tokenId
。但是,在其他用例(例如那些需要在双方之间签订法律合同的用例)中,可能需要单独的 uri
链接,因为 NFT 的元数据可能需要将双方的信息存储在不可变的存储器上。
将控制权还给用户
传统的订阅模式,尤其是流媒体服务,订阅模式的控制权完全掌握在中心服务提供商手中。此提案为去中心化服务提供了一种标准方式,将控制权还给其用户。因此,每个用户都能够开发自己的订阅生态系统,并根据自己及其订阅者的需求对其进行管理。
向后兼容性
订阅代币合约可以与 EIP-20 规范完全兼容,例如,允许从一个订阅者转移到另一个订阅者或用户。EIP-20 方法 name
、symbol
和 balanceOf
已经是本提案规范的一部分,由实施者自行决定是否通过考虑自己的用例来实现 EIP-20 接口的其余部分。
使用订阅代币实际上是一种间接控制 NFT 生命周期的方式。因此,假设当 NFT 和订阅 NFT 的订阅代币合约由同一平台或去中心化应用程序部署时,此安排效果最佳。它不得对尚未将订阅代币批准为运营商的现有 NFT 产生影响或依赖关系。事实上,在这种情况下,任何其他方都不会意识到这一点,并且任何 NFT 生命周期依赖关系都将被忽略,因此无论如何都不应起作用。为此,本提案规定,“nft”必须已批准 subscriptionToken
合约地址作为运营商。
安全考虑
服务提供商通常在订阅者使用服务之前预先收到订阅者付款是正常的。事实上,此提案通过 deposit
方法遵循此要求。因此,服务提供商有可能建立、接收存款,然后不向其订阅者提供或提供不良服务。这种情况在传统世界中也会发生,而本提案并未涵盖如何解决此问题。
subscribeToNFT
方法采用一个 uri
参数链接到 nft
元数据。如果在中心化存储上存储,所有者可能会更改元数据,或者元数据可能会被黑客入侵,这也是 vanilla NFT 合约的问题。但是,由于 uri
是在订阅时而不是部署时提供的,因此建议在用例需要时,实施者确保 uri
链接指向不可变存储。
版权
版权和相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Jules Lai (@julesl23), "ERC-4885: 订阅 NFT 和多代币 [DRAFT]," Ethereum Improvement Proposals, no. 4885, March 2022. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4885.