ERC-7832: 可持续的协作 NFT 收藏品
经济上可持续的协作 NFT 收藏品,具有动态费用和基于捐赠的互动。
Authors | Gustavo Lobo (@gflobo) |
---|---|
Created | 2024-12-04 |
Discussion Link | https://ethereum-magicians.org/t/erc-7832-sustainable-nft-collections/22201 |
Requires | EIP-721 |
摘要
本 EIP 提出了一种标准,用于为基于 ERC-721 构建的协作模型上的收藏品创建经济上可持续的 NFT 治理。它引入了动态铸造费用、基于角色的访问控制和基于捐赠的参与模型,以增强创建者与社区之间的互动。这些机制旨在平衡稀缺性,激励有意义的参与,并确保创建者和贡献者的可持续增长。
该模型将“经济上可持续”定义为:通证的铸造价值、创建者订阅费以及每个渐进折扣周期内的通证数量,只能由 ADMIN
用户自上次更新起每 30 天调整一次。这些机制可以防止过度的管理修改,这些修改可能会扰乱市场稳定,从而确保一致的价格发现并保持参与者的信心。通过协调激励措施并培养可预测性,该模型为参与和价值创造创建了一个强大的框架。
动机
随着 NFT 市场的成熟,创建者和用户面临的常见挑战之一是供应的通货膨胀性质以及缺乏有效机制来有意义地吸引社区。建立在协作模型上的 NFT 收藏品需要治理系统,这些系统可以赋予所有利益相关者(创建者、贡献者和收藏家)权力,同时保持长期的经济可持续性。引入此提案旨在通过为 NFT 收藏品培育更动态、灵活和透明的系统来解决这些问题。本 EIP 通过引入以下内容来解决这些差距:
- 基于角色的访问:在确保管理员透明治理的同时,增强创建者的能力。
- 动态铸造费用:使通证成本与用户活动和所有权保持一致。
- 基于捐赠的参与:鼓励对创建者的贡献。
规范
本文档中的关键词“必须”,“禁止”,“需要”,“应当”,“不应当”,“推荐”,“可以”和“可选”应按照 RFC 2119 中的描述进行解释。
必须实现以下接口。
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.20;
interface IERC7832 is IERC721 {
// Events
event CreatorTermsUpdated(
uint256 mintBaseFee,
uint256 creatorSignatureFee,
uint256 maxMintsPerUserInCycle);
event DonationReceived(address from, address to, uint256 amount);
// Function to get the current token ID
function currentTokenId() external view returns (uint256);
// Function to get the current mint base fee
function mintBaseFee() external view returns (uint256);
// Function to get the creator signature fee
function creatorSignatureFee() external view returns (uint256);
// Function to get the maximum mints a user can perform during his progressive discount cycle per mint
function maxMintsPerUserInCycle() external view returns (uint256);
// Function to get the last update timestamp
function lastUpdateTimestamp() external view returns (uint256);
// Function to get the update interval constant (30 days)
function UPDATE_INTERVAL() external pure returns (uint256);
// Function to get the CREATOR_ROLE
function getCreatorSignature() external payable;
// Function to get the CONTRIBUTOR_ROLE identifier
function CONTRIBUTOR_ROLE() external pure returns (bytes32);
// Function to get CREATOR_ROLE identifier
function CREATOR_ROLE() external pure returns (bytes32);
// Function to get ADMIN_ROLE identifier
function ADMIN_ROLE() external pure returns (bytes32);
// Function to check the number of mints a user has performed in their current cycle of progressive discounts
function mintsPerUserInCycle(address user) external view returns (uint256);
// Allow users to donate ETH to a specific creator in the system.
function donate(address creator) external payable;
// Allow users to check their mint fee
function mintFee() external view returns (uint256);
// Allow token owners to burn their tokens
function burn(uint256 tokenId) external;
// Allow ADMIN_ROLE pause the contract
function pause() external;
// Allow ADMIN_ROLE unpause the contract
function unpause() external;
// Allow CREATOR_ROLE to mint
function safeMint(string memory uri) external payable;
// Allow ADMIN_ROLE to update contract terms
function updateTerms(
uint256 mintBaseFee,
uint256 creatorSignatureFee,
uint256 maxMintsPerUserInCycle
) external;
// Allow ADMIN_ROLE to withdraw funds from the contract
function withdraw(uint256 amount) external;
}
currentTokenId()
描述:
跟踪系统中的当前通证 ID。 也可以用于确定系统中已铸造多少个通证。
mintBaseFee()
描述: 铸造通证的基本费用,由用户支付以创建新的通证。
creatorSignatureFee()
描述: 用户获取创建者签名所需的费用,允许他们在系统中成为创建者。
maxMintsPerUserInCycle()
描述: 用户在其当前的渐进折扣周期内每次铸造可以执行的最大铸造次数。 一旦超过限制,用户的铸造计数将重置为零。
lastUpdateTimestamp()
描述: 上次更新合约条款(例如,铸造费用和创建者签名费用)的时间戳。 它用于确定何时可以再次更新合约条款。
UPDATE_INTERVAL()
描述: 合约条款更新之间的时间间隔。必须固定为 30 天。
ADMIN_ROLE()
描述: 系统中管理员的角色标识符。
要求:
- 必须在构造函数中分配给
msg.sender
。
CREATOR_ROLE()
描述: 系统中创建者的角色标识符。
要求:
- 必须在构造函数中分配给
msg.sender
。
CONTRIBUTOR_ROLE()
描述: 系统中贡献者的角色标识符。
mintsPerUserInCycle(address user)
描述: 跟踪用户在其当前的渐进折扣周期中执行的铸造次数。 它用于强制执行每个用户的最大铸造限制。
CreatorTermsUpdated(uint256 mintBaseFee, uint256 creatorSignatureFee, uint256 maxMintsPerUserInCycle)
描述:
当与铸造相关的合约条款由 ADMIN_ROLE
更新时发出。
DonationReceived(address from, address to, uint256 amount)
描述: 当用户向创建者捐赠 ETH 时发出。 此事件跟踪捐赠的详细信息,包括捐赠者的地址、接收者的地址和捐赠金额。
参数:
from
:进行捐赠的用户的地址。to
:接收捐赠的创建者的地址。amount
:捐赠的 ETH 金额。
safeMint(string memory uri)
描述: 允许调用者使用提供的 URI 将新通证铸造到他们的地址。
要求:
- 调用者必须具有 CREATOR_ROLE。
- 用户必须支付铸造费用,该费用根据他们之前的铸造活动而动态变化。
- 如果超过铸造限制,用户的铸造计数应重置为零。
- 推荐要求在使用此函数之前合约未暂停。
mintFee()
描述: 根据调用者在他当前的每次铸造折扣周期中执行的铸造次数,计算并返回调用者必须支付的当前铸造费用。推荐该费用使用对数减少来平滑调整费用。
公式: ```math \text{mintFee} = \begin{cases} 0, & \text{if msg.sender has the ADMIN_ROLE} \ \frac{\text{mintBaseFee}}{\log_x(\text{userMints})}, & \text{if } \text{userMints} > 1 \ \frac{\text{mintBaseFee}}{1}, & \text{if } \text{userMints} <= 1 \end{cases}
> 注意:请注意,由于 Solidity 具有浮点数的特性,返回的对数始终四舍五入为整数。
**要求:**
- 铸造费用**必须**由调用者支付。
#### `donate(address creator)`
**描述:**
允许用户向创建者捐赠 ETH,以帮助资助他们的活动。 进行捐赠后,捐赠者**应**收到 **CONTRIBUTOR_ROLE**。
**要求:**
- 提供的地址**必须**是有效的创建者(具有 **CREATOR_ROLE**)。
- `msg.sender`**不得**与 `creator` 相同。
- 捐赠金额**必须**大于零。
- **必须**在处理捐赠后发出 `DonationReceived` 事件。
#### `getCreatorSignature()`
**描述:**
允许用户通过支付所需费用来获取创建者的签名。
**要求:**
- 调用者**必须**支付创建者签名费用。
- 付款后,调用者**应**被授予 **CREATOR_ROLE**。
- **推荐** 要求在使用此函数之前合约未暂停。
#### `updateTerms(uint256 mintBaseFee, uint256 creatorSignatureFee, uint256 maxMintsPerUserInCycle)`
**描述:**
允许管理员更新铸造费用、创建者签名费用以及渐进折扣周期中每个用户的最大铸造次数。
**要求:**
- 只有 `ADMIN_ROLE`**必须**调用此函数。
- **必须**在合约构造函数中调用,作为合约条款的首次更新。
- 在可以进行另一次更新之前,**应**遵守更新间隔周期。
- 更新合约条款后,**必须**发出 `CreatorTermsUpdated` 事件。
#### `withdraw(uint256 amount)`
**描述:**
允许 `ADMIN_ROLE` 从合约中提取 ETH。
**要求:**
- 只有 `ADMIN_ROLE`**必须**调用此函数。
#### `burn(uint256 tokenId)`
**描述:**
允许通证的所有者销毁(破坏)由 `tokenId` 指定的通证。
**要求:**
- 调用者**必须**是通证的所有者。
#### `pause()`
**描述:**
允许 `ADMIN_ROLE` 暂停合约,禁用某些功能。
**要求:**
- 只有 `ADMIN_ROLE`**应**调用此函数以暂停合约。
#### `unpause()`
**描述:**
允许 `ADMIN_ROLE` 取消暂停合约,重新启用功能。
**要求:**
- 只有 `ADMIN_ROLE`**应**调用此函数以取消暂停合约。
## 原理
以下是设计选择的关键考虑因素和理由:
1. **访问控制**
- **问题**:在协作 NFT 系统中,必须确保关键合约函数仅由授权用户执行,以防止滥用或操纵。 如果没有适当的访问控制,则存在任何人都可以修改关键参数(例如铸造费用、条款或合约暂停)的风险,这可能导致不稳定或某些用户的不公平优势。
- **解决方案**:通过引入基于角色的访问控制,此标准可确保只有受信任的参与者才能执行敏感操作。 管理员负责更新合约条款、暂停或取消暂停合约以及提取资金,而创建者可以管理自己的收藏品并获得捐赠。 这可以防止可能损害市场稳定或削弱社区信任的任意更改。
2. **动态铸造费用**
- **问题**:固定的铸造费用通常会导致囤积和不成比例的所有权,从而限制了对 NFT 的公平访问。
- **解决方案**:通过根据定义的<u>铸造周期</u>内的用户活动动态调整铸造费用,我们确保通过<u>随着铸造获得逐步折扣</u>来激励用户与平台互动。 使用对数减少铸造费用可确保该过程是渐进的,从而防止市场操纵并随着时间的推移保持稀缺性。
3. **基于捐赠的参与**
- **问题**:创建者通常缺乏可持续的模型来促进社区参与和接受捐款。
- **解决方案**:捐赠系统为贡献者提供了一种透明的方式来直接支持他们最喜欢的创作者。 例如,这可用于在未来的交易中归属收益。 这鼓励了更深入的参与并加强了创建者与其社区之间的关系。
### 向后兼容性
此 EIP 与 ERC-721 完全兼容。 动态铸造费用、捐赠系统等扩展是模块化的,不会影响现有的 NFT 通证功能。
### 参考实现
#### `mintFee()`
```solidity
function mintFee() public view returns (uint256) {
if (hasRole(ADMIN_ROLE, msg.sender)) return 0;
uint256 userMints = mintsPerUserInCycle(msg.sender);
uint256 divisor = userMints <= 1 ? 1 : Math.log2(userMints);
return mintBaseFee / divisor;
}
safeMint(string memory uri)
function safeMint(string memory uri)
public
payable
override
onlyIfNotPaused
nonReentrant
onlyRole(CREATOR_ROLE)
{
bool userMintsExceeded = mintsPerUserInCycle(msg.sender) + 1 > maxMintsPerUserInCycle;
require(msg.value >= mintFee(), "Not enough ETH!");
uint256 tokenId = currentTokenId++;
_safeMint(msg.sender, tokenId);
_setTokenURI(tokenId, uri);
if(userMintsExceeded){
mintsPerUserInCycle(msg.sender) = 0;
}
mintsPerUserInCycle(msg.sender)++;
}
安全考虑
- 重入保护:
推荐确保函数
safeMint
、withdraw
和donate
受到保护,免受重入攻击。 - 暂停状态: 管理员必须能够在紧急情况下暂停合约,以防止不必要的操作并减轻不确定时期的风险。
- 销毁安全性: 确保只有通证的所有者才能销毁它,从而降低恶意合约或未经授权的用户销毁属于其他人的通证的风险。 销毁行为仅限于所有权函数,通过防止意外或滥用的通证破坏来增强安全性。
版权
版权和相关权利已通过 CC0 放弃。
Citation
Please cite this document as:
Gustavo Lobo (@gflobo), "ERC-7832: 可持续的协作 NFT 收藏品 [DRAFT]," Ethereum Improvement Proposals, no. 7832, December 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7832.