ERC-7595: 抵押 NFT
ERC-721扩展,支持使用基于ERC-20的代币进行抵押。
Authors | 571nKY (@571nKY), Cosmos (@Cosmos4k), f4t50 (@f4t50), Harpocrates (@harpocrates555) |
---|---|
Created | 2023-03-13 |
Discussion Link | https://ethereum-magicians.org/t/collateralized-nft-standard/18097 |
Requires | EIP-20, EIP-721 |
Table of Contents
摘要
本提案建议对 ERC-721 进行扩展,以允许使用 ERC-20 代币列表进行抵押。该 ERC 集合的所有者可以同时持有原生代币和 ERC-20 代币,其中 ownerOf
tokenId 能够解锁相关部分的底层 ERC-20 余额。
动机
NFT 金融的新兴趋势侧重于 NFT 底价,以使 NFT 的市场价值能够作为借贷协议中的抵押品。NFT 底价容易受到 NFT 市场供需动态的影响,其特点是与更广泛的加密货币市场相比,波动性更高。此外,特定 NFT 集合中潜在的价格操纵可能会人为抬高 NFT 市场价格,从而影响借贷协议考虑的底价。仅仅依赖基于市场价值的 NFT 底价既不可预测也不可靠。
此 ERC 解决了加密社区在使用基于 ERC-721 的集合和资产时遇到的各种挑战。此 ERC 带来了诸多优势,例如由有形资产支持的可持续 NFT 版税、链上可验证的底价,以及为 NFT 集合创建者引入额外的货币化途径。
预设
-
基本预设允许评估指定 NFT 资产的链上可验证价格底线。
-
动态预设便于根据指定 NFT 资产的预定义抵押规则,在链上修改 tokenURI。
-
通过版税预设,NFT 集合创建者可以获得资产所有者和外部所有账户 (EOA) 之间交易以及与智能合约交易的版税支付。
-
VRF 预设允许使用 Chainlink 的可验证随机函数 (VRF) 在多个 NFT 资产持有者之间分配抵押品。
扩展到现有的基于 ERC-721 的集合
对于许多无法重新部署的基于 ERC-721 的集合,我们建议实施由智能合约体现的抽象层。该智能合约将复制此 ERC 标准的所有功能,并通过映射授予对抵押品的访问权限。
规范
新的 NFT 集合的 ERC 标准
interface IERC721Envious is IERC721 {
event Collateralized(uint256 indexed tokenId, uint256 amount, address tokenAddress);
event Uncollateralized(uint256 indexed tokenId, uint256 amount, address tokenAddress);
event Dispersed(address indexed tokenAddress, uint256 amount);
event Harvested(address indexed tokenAddress, uint256 amount, uint256 scaledAmount);
/**
* @dev 包含两个元素的数组。每个元素代表从抵押品中提取的佣金百分比。
* 第一个元素代表抵押佣金。第二个元素代表取消抵押佣金。
* 它们中的每一个都应有 3 位小数的缓冲区,例如 1000 = 1%。
*
* @param uint 数组中值的 256 索引。
*/
function commissions(uint256 index) external view returns (uint256);
/**
* @dev “黑洞”是任何保证发送到它的代币不会被检索的地址。
* 注意:某些代币在转移到零地址时会恢复。
*
* @return address 黑洞的地址。
*/
function blackHole() external view returns (address);
/**
* @dev 将用于收集所收集佣金的代币。
*
* @return address 代币的地址。
*/
function communityToken() external view returns (address);
/**
* @dev 可用于收集的代币池。
*
* @param uint256 数组中的索引。
* @return address 代币的地址。
*/
function communityPool(uint256 index) external view returns (address);
/**
* @dev 可用于收集的代币余额。
*
* @param address 代币的地址。
* @return uint256 代币余额。
*/
function communityBalance(address tokenAddress) external view returns (uint256);
/**
* @dev 已分散的代币数组。
*
* @param uint256 数组中的索引。
* @return address 分散代币的地址。
*/
function disperseTokens(uint256 index) external view returns (address);
/**
* @dev 已分散的代币数量。
*
* @param address 代币的地址。
* @return uint256 代币余额。
*/
function disperseBalance(address tokenAddress) external view returns (uint256);
/**
* @dev 已从分散中提取的代币数量。
*
* @param address 代币的地址。
* @return uint256 已提取的代币总数。
*/
function disperseTotalTaken(address tokenAddress) external view returns (uint256);
/**
* @dev 每个 tokenId 已提取的分散量。
*
* @param tokenId 单元的唯一标识符。
* @param address 代币的地址。
* @return uint256 已提取的代币数量。
*/
function disperseTaken(uint256 tokenId, address tokenAddress) external view returns (uint256);
/**
* @dev `tokenId` 到之前已抵押的代币地址的映射。
*
* @param tokenId 单元的唯一标识符。
* @param 数组中的索引。
* @return address 代币的地址。
*/
function collateralTokens(uint256 tokenId, uint256 index) external view returns (address);
/**
* @dev 存储在 `tokenId` 下的代币余额。
*
* @param tokenId 单元的唯一标识符。
* @param address 代币的地址。
* @return uint256 代币余额。
*/
function collateralBalances(uint256 tokenId, address tokenAddress) external view returns (uint256);
/**
* @dev 用于收集的计算器函数。
*
* @param amount 要花费的 `communityToken` 数量
* @param address 要收集的代币的地址
* @return 基于输入的收集金额
*/
function getAmount(uint256 amount, address tokenAddress) external view returns (uint256);
/**
* @dev 收集以 `communityToken` 交换收集的佣金费用。
*
* @param amounts[] 要抵押的数量数组
* @param address[] 代币地址数组
*/
function harvest(uint256[] memory amounts, address[] memory tokenAddresses) external;
/**
* @dev 使用不同的代币和数量抵押 NFT。
*
* @param tokenId 特定 NFT 的唯一标识符
* @param amounts[] 要抵押的数量数组
* @param address[] 代币地址数组
*/
function collateralize(
uint256 tokenId,
uint256[] memory amounts,
address[] memory tokenAddresses
) external payable;
/**
* @dev 提取基础抵押品。
*
* 要求:
* - 仅 NFT 所有者
*
* @param tokenId 特定 NFT 的唯一标识符
* @param amounts[] 要抵押的数量数组
* @param address[] 代币地址数组
*/
function uncollateralize(
uint256 tokenId,
uint256[] memory amounts,
address[] memory tokenAddresses
) external;
/**
* @dev 在所有现有代币中拆分抵押品。
*
* @param amounts[] 要在所有 NFT 所有者之间分散
* @param address[] 要分散的代币的地址
*/
function disperse(uint256[] memory amounts, address[] memory tokenAddresses) external payable;
}
已经部署的 NFT 集合的抽象层
interface IEnviousHouse {
event Collateralized(
address indexed collection,
uint256 indexed tokenId,
uint256 amount,
address tokenAddress
);
event Uncollateralized(
address indexed collection,
uint256 indexed tokenId,
uint256 amount,
address tokenAddress
);
event Dispersed(
address indexed collection,
address indexed tokenAddress,
uint256 amount
);
event Harvested(
address indexed collection,
address indexed tokenAddress,
uint256 amount,
uint256 scaledAmount
);
/**
* @dev totalCollections 函数返回注册集合的总数。
*
* @return uint256 注册集合的数量。
*/
function totalCollections() external view returns (uint256);
/**
* @dev “黑洞”是任何保证发送到它的代币不会被检索的地址。
* 注意:某些代币在转移到零地址时会恢复。
*
* @param address 集合地址。
* @return address 黑洞的地址。
*/
function blackHole(address collection) external view returns (address);
/**
* @dev collections 函数基于集合索引输入返回集合地址。
*
* @param uint256 注册集合的索引。
* @return address 地址集合。
*/
function collections(uint256 index) external view returns (address);
/**
* @dev collectionIds 函数基于集合地址输入返回集合索引。
*
* @param address 集合地址。
* @return uint256 集合索引。
*/
function collectionIds(address collection) external view returns (uint256);
/**
* @dev specificCollections 函数返回特定集合是否遵循 ERC721 标准。
*
* @param address 集合地址。
* @return bool 特定集合。
*/
function specificCollections(address collection) external view returns (bool);
/**
* @dev 包含两个元素的数组。每个元素代表从抵押品中提取的佣金百分比。
* 第一个元素代表抵押佣金。第二个元素代表取消抵押佣金。
* 它们中的每一个都应有 3 位小数的缓冲区,例如 1000 = 1%。
*
* @param address 集合地址。
* @param uint256 数组中值的索引。
* @return uint256 收集的佣金。
*/
function commissions(address collection, uint256 index) external view returns (uint256);
/**
* @dev 将用于收集所收集佣金的代币。
*
* @param address 集合地址。
* @return address 代币的地址。
*/
function communityToken(address collection) external view returns (address);
/**
* @dev 可用于收集的代币池。
*
* @param address 集合地址。
* @param uint256 数组中的索引。
* @return address 代币的地址。
*/
function communityPool(address collection, uint256 index) external view returns (address);
/**
* @dev 可用于收集的代币余额。
*
* @param address 集合地址。
* @param address 代币的地址。
* @return uint256 代币余额。
*/
function communityBalance(address collection, address tokenAddress) external view returns (uint256);
/**
* @dev 已分散的代币数组。
*
* @param address 集合地址。
* @param uint256 数组中的索引。
* @return address 分散代币的地址。
*/
function disperseTokens(address collection, uint256 index) external view returns (address);
/**
* @dev 已分散的代币数量。
*
* @param address 集合地址。
* @param address 代币的地址。
* @return uint256 代币余额。
*/
function disperseBalance(address collection, address tokenAddress) external view returns (uint256);
/**
* @dev 已从分散中提取的代币数量。
*
* @param address 集合地址。
* @param address 代币的地址。
* @return uint256 已提取的代币总数。
*/
function disperseTotalTaken(address collection, address tokenAddress) external view returns (uint256);
/**
* @dev 每个 tokenId 已提取的分散量。
*
* @param address 集合地址。
* @param tokenId 单元的唯一标识符。
* @param address 代币的地址。
* @return uint256 已提取的代币数量。
*/
function disperseTaken(address collection, uint256 tokenId, address tokenAddress) external view returns (uint256);
/**
* @dev `tokenId` 到之前已抵押的代币地址的映射。
*
* @param address 集合地址。
* @param tokenId 单元的唯一标识符。
* @param 数组中的索引。
* @return address 代币的地址。
*/
function collateralTokens(address collection, uint256 tokenId, uint256 index) external view returns (address);
/**
* @dev 存储在 `tokenId` 下的代币余额。
*
* @param address 集合地址。
* @param tokenId 单元的唯一标识符。
* @param address 代币的地址。
* @return uint256 代币余额。
*/
function collateralBalances(address collection, uint256 tokenId, address tokenAddress) external view returns (uint256);
/**
* @dev 用于收集的计算器函数。
*
* @param address 集合地址。
* @param amount 要花费的 `communityToken` 数量。
* @param address 要收集的代币的地址。
* @return amount 基于输入的收集金额。
*/
function getAmount(address collection, uint256 amount, address tokenAddress) external view returns (uint256);
/**
* @dev setSpecificCollection 函数支持将任何与 ERC721 标准不兼容的集合添加到异常列表中。
*
* @param address 集合地址。
*/
function setSpecificCollection(address collection) external;
/**
* @dev registerCollection 函数授予任何与 ERC721 兼容的集合 Envious 功能,并简化
* 向所有 NFT 持有者分发初始最低分配。
*
* @param address 集合地址。
* @param address `communityToken` 的地址。
* @param uint256 抵押手续费,传入 / 1e5 * 100%。
* @param uint256 取消抵押手续费,传入 / 1e5 * 100%。
*/
function registerCollection(
address collection,
address token,
uint256 incoming,
uint256 outcoming
) external payable;
/**
* @dev 收集以 `communityToken` 交换收集的佣金费用。
*
* @param address 集合地址。
* @param amounts[] 要抵押的数量数组。
* @param address[] 代币地址数组。
*/
function harvest(
address collection,
uint256[] memory amounts,
address[] memory tokenAddresses
) external;
/**
* @dev 使用不同的代币和数量抵押 NFT。
*
* @param address 集合地址。
* @param tokenId 特定 NFT 的唯一标识符。
* @param amounts[] 要抵押的数量数组。
* @param address[] 代币地址数组。
*/
function collateralize(
address collection,
uint256 tokenId,
uint256[] memory amounts,
address[] memory tokenAddresses
) external payable;
/**
* @dev 提取基础抵押品。
*
* 要求:
* - 仅 NFT 所有者
*
* @param address 集合地址。
* @param tokenId 特定 NFT 的唯一标识符。
* @param amounts[] 要抵押的数量数组。
* @param address[] 代币地址数组。
*/
function uncollateralize(
address collection,
uint256 tokenId,
uint256[] memory amounts,
address[] memory tokenAddresses
) external;
/**
* @dev 在所有现有代币中拆分抵押品。
*
* @param address 集合地址。
* @param amounts[] 要在所有 NFT 所有者之间分散。
* @param address[] 要分散的代币的地址。
*/
function disperse(
address collection,
uint256[] memory amounts,
address[] memory tokenAddresses
) external payable;
}
理由
“Envious” 术语选择
我们建议采用术语“Envious”来描述使用此 ERC 标准铸造的任何 NFT 集合,或使用 EnviousHouse 抽象层的任何基于 ERC-721 的 NFT 集合。
使用多个代币进行 NFT 抵押
一些 Web3 项目主要使用一个 ERC-20 代币来抵押特定的 NFT 资产,从而导致 gas 费用增加和用户体验 (UX) 复杂化。
此 ERC 旨在支持在单个交易中使用多个 ERC-20 代币来抵押指定的 NFT 资产。
使用原生代币进行 NFT 抵押
每个 ERC-20 代币都具有不同的地址。但是,原生代币没有地址。为了解决这个问题,我们建议使用空地址 (0x0000000000000000000000000000000000000000
) 作为抵押期间原生代币的标识符,因为它消除了与智能合约地址发生冲突的可能性。
分散功能
我们实现了在单个交易中抵押特定 NFT 集合中的所有资产的功能。完整的抵押金额存入智能合约,使每个用户在添加或兑换该特定资产的抵押品时,都可以声明其各自的抵押品份额。
收集功能
每个 Envious NFT 集合都提供了一个选项,可以合并一个社区 ERC-20 代币,该代币可以兑换从抵押和取消抵押活动中累积的佣金。
BlackHole 实例
一些 ERC-20 代币实现禁止转移到空地址,因此有必要在收集交易中拥有可靠的销毁机制。blackHole
智能合约从流通供应中删除 ERC-20 communityTokens,以换取提取的佣金费用。
blackHole
旨在防止从自身转移任何代币,并且只能执行读取操作。它旨在与 Envious 扩展一起用于与佣金收集相关的实现中。
向后兼容性
建议对已经部署的基于 ERC-721 的 NFT 集合使用 EnviousHouse 抽象层。
安全考虑
Envious 可能会遇到与 ERC-721 相似的安全问题,例如 burn、添加资源、接受资源等功能中的隐藏逻辑。
版权
版权和相关权利通过 CC0 放弃。
Citation
Please cite this document as:
571nKY (@571nKY), Cosmos (@Cosmos4k), f4t50 (@f4t50), Harpocrates (@harpocrates555), "ERC-7595: 抵押 NFT [DRAFT]," Ethereum Improvement Proposals, no. 7595, March 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7595.