ERC-7929: PermaLink 资产绑定型代币
资产绑定型代币 (ABT) 永久绑定到另一个代币,称为 PermaLink-ABT。
Authors | Mihai Onila (@MihaiORO), Nick Zeman (@NickZCZ), Narcis Cotaie (@NarcisCRO) |
---|---|
Created | 2025-04-01 |
Discussion Link | https://ethereum-magicians.org/t/non-fungible-asset-bound-token/23175 |
Requires | EIP-721 |
Table of Contents
摘要
本标准引入了一种名为 PermaLink 资产绑定型代币 (PermaLink-ABT) 的代币子类。它们是更广泛的 资产绑定型代币 (ABT) 概念的特定实现。ABT 建立了一种新的所有权范式,其中一种资产可以拥有另一种资产,从而实现可组合的、嵌套的和类似于投资组合的代币结构,这些结构会随着时间的推移而共同发展。
PermaLink-ABT 实现了一种永久绑定机制,其中一个智能合约中的代币被不可逆转地链接到另一个合约中的代币。这些链接使用 assetBoundContract
接口镜像了关键状态数据,例如 ownerOf
、tokenId
、totalSupply
和 balanceOf
。传统的代币转移和批准功能被省略,以强制执行绑定资产之间的不变性和结构凝聚力。
PermaLink-ABT 没有使用 mint
函数,而是采用了一种 reveal
机制,该机制从预定义的供应中激活代币。这种方法实现了无需许可的绑定,并显著降低了 gas 成本。单个代币可以绑定多个 PermaLink-ABT,充当多个从属资产,形成一个统一的、可转移的单元,从而简化了跨数字身份、NFT 和现实世界资产 (RWA) 的资产流动性。
通过鼓励资产的可组合性而不是竞争,PermaLink-ABT 引入了一种动态的、面向未来的链上资产演进模型。
动机
以太坊上的传统所有权模型本质上是有限的。只有外部拥有的帐户 (EOA) 或智能合约才能拥有区块链资产。这造成了僵化,尤其是在区块链生态系统扩展到包括数字身份、代币化的现实世界资产 (RWA) 和 NFT 时。当前的智能合约本质上是静态的,这意味着一旦部署,它们就无法适应不断发展的系统、不可预见的用例或新的集成层。我们需要一种更灵活和模块化的所有权模型,以实现资产之间的动态交互。
本标准提出了 资产绑定型代币 (ABT) 作为解决这一挑战的方案。ABT 允许一个代币永久绑定到另一个跨合约的代币,从而创建一个动态、灵活和可组合的所有权模型。通过使代币能够一起移动和发展,ABT 为链上经济中的新可能性铺平了道路。以下用例说明了为什么需要 ABT:
-
链上身份系统
全球的政府和机构正在试点或实施基于区块链的身份系统、数字护照、国民身份证和可验证凭证,例如正在进行的欧洲区块链服务基础设施 (EBSI) 计划。这些系统通常需要跨多个注册表(例如,医疗保健、银行、投票)链接凭证。ABT 能够将身份链接的代币绑定到一个有凝聚力的单元中,以便它们一起移动,而不是需要手动协调和转移。这确保了身份链接的资产保持互连和动态,从而可以更轻松地管理和更新链接数据,因为用户可以与各种系统进行交互。 -
现实世界资产 (RWA) 所有权结构
代币化的企业和资产(例如,土地、设备、商品)需要灵活的所有权模型。这些是动态的——企业收购、剥离和重组其持股和各种资产。ABT 允许合约表示复杂的、不断发展的所有权层次结构,其中嵌套资产遵循其父实体结构的变化(例如,一家农业公司收购新土地或一家 IT 公司与另一家公司合并并继承知识产权)。ABT 确保企业可以高效地管理和在链上转移资产,而不会受到僵化的智能合约的限制。 -
制造和供应链管理
供应链涉及多层资产:原材料 → 零件 → 产品 → 包装 → 容器。区块链的透明度非常宝贵,但为每个阶段创建单独的代币或智能合约的传统方法效率低下且成本高昂。ABT 通过跨供应链链接代币来简化此过程,从而可以在构建产品时聚合它们(例如,将鞋子装在盒子里,将盒子放在托盘上,将托盘装入容器中),并在它们通过不同的阶段时分解它们(例如,卸载容器,拆分托盘,拆开盒子)。这种动态链接和取消链接减少了冗余,保持了透明的不可变记录,并确保了无缝跟踪,同时最大限度地降低了 gas 成本。通过实现资产在整个供应链中的高效流动,ABT 有助于降低复杂性并提供整个过程的统一、实时视图。 -
NFT 生态系统优化
NFT 项目通常通过启动二级集合(例如,附加版本、特别发行)来扩展。如果没有 ABT,这会导致价值分散和用户混淆,因为较旧和较新的资产会相互竞争。ABT 允许将新的 NFT 绑定到原始 NFT,从而提高它们的价值,同时保持统一的生态系统。这加强了流动性并保留了市场指标,确保原始集合的价值得到保留并受到较新资产的支持,从而使创建者和收藏家都受益。 -
创作者的新机会
ABT 使创作者能够在现有资产之上无需许可地进行构建,而无需原始智能合约的所有权或许可。这开启了创意表达的新浪潮,艺术家可以增强和改进 NFT(例如,添加新的视觉效果、音频或交互层)并在现有集合上进行协作。此类贡献可以通过共享版税、寄售或协作升级来产生新的收入来源。所有者也可以从中受益,因为绑定的增强功能可以增加其持股的内在价值,尤其是在涉及已建立的创作者或跨集合协作的项目中。
本质上,ABT 引入了一个框架,其中代币是链接的而不是拥有的。这允许动态和不断发展的资产系统,其中资产和谐地一起移动。如果绑定代币移动,则所有关联的 ABT 也会随之移动,从而确保无缝更新并减少手动转移的需要。这种创新将传统的智能合约从静态存储库转变为能够适应不断变化的用例、技术和业务模型的动态、不断发展的系统。
PermaLink-ABT 实现通过强制一个代币与另一个代币之间的永久绑定来进一步推动 ABT 模型 - 无论是另一个 ABT、NFT 还是 NFKBT。这种永久绑定确保代币可以作为单个单元进行转移,从而降低了复杂性和 gas 费用。PermaLink-ABT 没有依赖传统的铸造,而是使用 reveal
机制,从预定义的供应中激活代币。这降低了 gas 成本并鼓励了资产的有效链接,从而实现了跨多个行业的更大可组合性。
PermaLink-ABT 通过允许将多个从属代币链接到单个绑定代币来整合资产价值,从而提供增强的可组合性并减少碎片化。通过仅需要转移绑定代币,所有关联的资产都会同步移动,从而更容易管理投资组合并将资产组一起移动。无论对于数字身份、RWA、NFT 还是其他链上资产,这种方法都有助于跨生态系统的协作、价值累积和兼容性。
规范
IERC7929
(代币接口)
注意:
- 以下规范使用 Solidity
0.8.27
(或更高版本)的语法
interface IERC7929 {
event AssetBoundContractSet(address assetBoundContract);
function ownerOf(uint256 tokenId) external view returns (address);
function tokenExists(uint256 tokenId) external view returns (bool);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
}
事件
AssetBoundContractSet
事件
当合约部署并绑定到 assetBoundContract
时发出
event AssetBoundContractSet(address assetBoundContract);
函数
必须实现下面详细描述的函数。
ownerOf
返回 tokenId
指定的 NFT 的所有者。将从 assetBoundContract
读取所有者并返回它。
function ownerOf(uint256 tokenId) external view returns (address);
tokenExists
如果从 assetBoundContract
读取的代币存在,则返回 true。
代币通常在铸造时开始存在,并在销毁时停止存在。
function tokenExists(uint256 tokenId) external view returns (bool);
totalSupply
获取 assetBoundContract
存储的代币总数
function totalSupply() external view returns (uint256);
balanceOf
返回所有者在 assetBoundContract
中拥有的 NFT 数量。
function balanceOf(address owner) external view returns (uint256);
IERC7929Reveal
(可选代币接口)
注意:
- 以下规范使用 Solidity
0.8.27
(或更高版本)的语法 - Reveal 扩展对于 ERC-7929 合约是可选的
interface IERC7929Reveal is IERC7929 {
event TokenRevealed(uint256 tokenId);
function reveal(uint256[] calldata tokenIds) external payable;
}
事件
TokenRevealed
事件
当 tokenId
被揭示时发出
event TokenRevealed(uint256 tokenId);
函数
必须实现下面详细描述的函数。
reveal
应该实现 reveal
函数,以允许按需激活预先分配的代币。
与传统的铸造相比,此方法降低了 gas 消耗,并简化了代币激活机制。
function reveal(uint256[] calldata tokenIds) external payable;
理论原理
PermaLink-ABT 的设计围绕着实现永久代币绑定,同时针对 gas 效率、可组合性和安全所有权结构进行优化。我们采用了 assetBoundContract
接口来镜像来自绑定代币合约的基本元数据,例如 ownerOf
、tokenId
、totalSupply
和 balanceOf
。这确保了 PermaLink-ABT 与它们绑定的资产保持同步,而无需复制逻辑或手动更新。镜像还确保了跨合约的可追溯性和可见性,允许观察者和链下系统可靠地解释代币关系。为了保持债券的永久性,省略了标准的 transfer
和 approve
方法。这种不变性保证了 PermaLink-ABT 一旦被揭示,就无法与它们绑定的资产分离。如果主代币移动,所有附加的 PermaLink-ABT 也会随之移动。此行为支持可组合性、价值聚合和一致的所有权逻辑。
考虑的另一种替代方案是通过选择加入转移函数或白名单来允许灵活的转移机制。但是,这引入了不必要的复杂性,并破坏了永久性的核心原则。它还增加了代币不同步、意外碎片化以及合约实现中安全漏洞的风险。相比之下,当前的设计提供了更简单、更强大的基础。
通过实现 可选的 reveal
函数来代替传统的 mint
函数,它可以降低 gas 成本,并简化代币部署者和所有者的链上状态更改,从而使 ABT 绑定到它。与在运行时创建代币并产生更高 gas 费用的铸造不同,reveal
函数映射存储在数组或映射中的预先分配的代币。这允许按需激活代币,而无需动态代币创建的开销。因此,代币发行者可以提前准备和存储整个供应,用户稍后可以根据需要揭示和绑定代币。这种方法符合投资组合绑定和资产层次结构的使用案例,在这些案例中,可能需要高效地激活和绑定大量代币。
PermaLink-ABT 强制执行具有不可变关系的严格单向绑定,使其特别适用于身份系统、现实世界资产 (RWA) 结构和投资组合锁定的 NFT 等用例。它们充当现有代币的永久附加扩展,从而降低了复杂性并避免了冗余合约逻辑。这种方法还提供了一种更清洁、更安全的方式来增强现有资产,同时保持跨各种区块链用例的兼容性。此标准有意保持最小化,以确保广泛的兼容性和灵活性。开发人员可以扩展专门用例的基本逻辑,例如嵌入版税拆分、升级路径或链接到动态数据馈送,而无需更改底层的 PermaLink 机制。
参考实现
ERC7929
(代币实现)
注意:
- 接口 ID 为 (
0x0b76916c
) - 调用者必须处理来自
returns (bool success)
的false
。调用者不得假设永远不会返回false
!
contract ERC7929 is IERC165, ERC721Enumerable, Ownable, IERC7929 {
ERC721Enumerable public assetBoundContract;
constructor(
address _assetBoundContract,
string memory _name,
string memory _symbol
) ERC721(_name, _symbol) {
assetBoundContract = ERC721Enumerable(_assetBoundContract);
emit AssetBoundContractSet(_assetBoundContract);
}
///////////////////////////////////////////////////////////////
// region EIP-165 Implementation
///////////////////////////////////////////////////////////////
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721Enumerable, IERC165) returns (bool) {
return
interfaceId == type(IERC7929).interfaceId ||
super.supportsInterface(interfaceId);
}
///////////////////////////////////////////////////////////////
// endregion
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// region Modifiers
///////////////////////////////////////////////////////////////
modifier tokensMustExist(uint256[] calldata tokenIds) {
for (uint256 i = 0; i < tokenIds.length; i++) {
require(tokenExists(tokenIds[i]), "ERC7929: Token does not exist");
}
_;
}
///////////////////////////////////////////////////////////////
// endregion Modifiers
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// region mirror functions
///////////////////////////////////////////////////////////////
function ownerOf(
uint256 tokenId
)
public
view
virtual
override(ERC721, IERC7929, IERC721)
returns (address)
{
return assetBoundContract.ownerOf(tokenId);
}
function tokenExists(uint256 tokenId) public view virtual returns (bool) {
return assetBoundContract.ownerOf(tokenId) != address(0);
}
function totalSupply()
public
view
virtual
override(ERC721Enumerable, IERC7929)
returns (uint256)
{
return assetBoundContract.totalSupply();
}
function balanceOf(
address owner
)
public
view
virtual
override(ERC721, IERC7929, IERC721)
returns (uint256)
{
return assetBoundContract.balanceOf(owner);
}
///////////////////////////////////////////////////////////////
//endregion
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//region Disabling approve and transfer functions to prevent transfers of ABT tokens
///////////////////////////////////////////////////////////////
function approve(address, uint256) public pure override(ERC721, IERC721) {
revert("ERC7929: Approvals not allowed");
}
function setApprovalForAll(
address,
bool
) public pure override(ERC721, IERC721) {
revert("ERC7929: Approvals not allowed");
}
function transferFrom(
address,
address,
uint256
) public pure override(ERC721, IERC721) {
revert("ERC7929: Transfers not allowed");
}
function safeTransferFrom(
address,
address,
uint256
) public pure override(ERC721, IERC721) {
safeTransferFrom(address(0), address(0), 0, "");
}
function safeTransferFrom(
address,
address,
uint256,
bytes memory
) public pure override(ERC721, IERC721) {
revert("ERC7929: Transfers not allowed");
}
///////////////////////////////////////////////////////////////
//endregion
///////////////////////////////////////////////////////////////
}
IERC7929Reveal
(代币实现)
注意:
- 这是 ERC-7929 合约的可选扩展
- 接口 ID 为 (
0xb93f208a
) - 调用者必须处理来自
returns (bool success)
的false
。调用者不得假设永远不会返回false
!
contract ERC7929Reveal is ERC7929, IERC7929Reveal {
mapping(uint256 => bool) public isRevealed;
constructor(
address _assetBoundContract,
string memory _name,
string memory _symbol
) ERC7929(_assetBoundContract, _name, _symbol) {}
///////////////////////////////////////////////////////////////
// region EIP-165 Implementation
///////////////////////////////////////////////////////////////
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool) {
return
interfaceId == type(IERC7929Reveal).interfaceId ||
super.supportsInterface(interfaceId);
}
///////////////////////////////////////////////////////////////
// endregion
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// region Modifiers
///////////////////////////////////////////////////////////////
modifier tokensMustNotBeRevealed(uint256[] calldata tokenIds) {
for (uint256 i = 0; i < tokenIds.length; i++) {
require(
!isRevealed[tokenIds[i]],
"ERC7929: Token already revealed"
);
}
_;
}
///////////////////////////////////////////////////////////////
// endregion Modifiers
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// region mirror functions
///////////////////////////////////////////////////////////////
function ownerOf(
uint256 tokenId
) public view override(ERC7929, IERC7929) returns (address) {
return super.ownerOf(tokenId);
}
function tokenExists(
uint256 tokenId
) public view override(ERC7929, IERC7929) returns (bool) {
return super.tokenExists(tokenId);
}
function totalSupply()
public
view
override(ERC7929, IERC7929)
returns (uint256)
{
return super.totalSupply();
}
function balanceOf(
address owner
) public view override(ERC7929, IERC7929) returns (uint256) {
return super.balanceOf(owner);
}
///////////////////////////////////////////////////////////////
//endregion
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
//region Reveal function to reveal the token URI for a given token ID(s)
///////////////////////////////////////////////////////////////
function reveal(
uint256[] calldata tokenIds
)
public
payable
virtual
tokensMustExist(tokenIds)
tokensMustNotBeRevealed(tokenIds)
{
for (uint256 i = 0; i < tokenIds.length; i++) {
isRevealed[tokenIds[i]] = true;
emit TokenRevealed(tokenIds[i]);
}
}
///////////////////////////////////////////////////////////////
//endregion
///////////////////////////////////////////////////////////////
}
安全注意事项
PermaLink-ABT 链接到另一个非同质化代币。如果个人失去对这个代币的访问权限,我们称之为绑定代币,他们也会失去对已绑定到它的所有 PermaLink-ABT 的访问权限。这引入了一个重要的安全注意事项:绑定资产的全部价值取决于绑定代币的完整性和可用性。
为了减轻这种风险,我们强烈建议使用诸如 ERC-6809 这样的标准,这是一个 非同质化密钥绑定代币,它引入了链上双因素身份验证 (2FA)。ERC-6809 允许用户将敏感代币(如 PermaLink-ABT)绑定到安全的身份层,并具有完整的恢复机制。如果用户失去对其原始钱包的访问权限或与恶意合约交互,ERC-6809 提供了一个 safeFallback 函数来重新建立控制。
本质上,ERC-6809 的所有安全保证都扩展到绑定到它的任何 PermaLink-ABT。这种分层安全模型不仅可以防止丢失,还可以确保高价值绑定资产的可恢复性和长期生存能力。强烈建议实施 PermaLink-ABT 的开发人员集成此标准或类似标准,以便为用户提供强大的安全基础。
版权
版权和相关权利通过 CC0 放弃。
Citation
Please cite this document as:
Mihai Onila (@MihaiORO), Nick Zeman (@NickZCZ), Narcis Cotaie (@NarcisCRO), "ERC-7929: PermaLink 资产绑定型代币 [DRAFT]," Ethereum Improvement Proposals, no. 7929, April 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7929.