以太坊 - 如何创建和部署一个Token绑定账户(ERC-6551) - Quicknode

  • QuickNode
  • 发布于 2024-04-06 17:27
  • 阅读 23

本文介绍了 ERC-6551 提案,该提案使得非同质化代币 (NFT) 可以作为“钱包”进行资产管理,支持与其他智能合约的交互。通过使用 Hardhat 和 OpenZeppelin,读者可以学习如何创建和部署符合 ERC-6551 标准的代币,并了解 Token Bound Account 的构建和操作流程。

概述

想象一下,如果你持有的 NFT 不仅可以代表资产本身,还可以充当“钱包”,允许你的资产与其他智能合约交互,并在其内部存储其他数字资产。一个新的 以太坊改进提案ERC-6551:非同质化代币绑定账户 有望不久在以太坊上实现这一功能。本文将介绍 ERC-6551 提案的具体细节,并帮助你了解如何使用 Hardhat 和 OpenZeppelin 创建和部署符合 ERC-6551 规范的代币。

你将需要的内容

  • 以太坊智能合约 的基本理解
  • ERC-721ERC-1155 标准的基本理解
  • 一个 MetaMask 钱包或访问你的公/private 键
  • Sepolia 测试网的 ETH(你可以在 这里 获取一些)
  • 一个基于网络的浏览器(例如 Chrome)

你将要做的事情

今天的 NFT & 代币标准

今天的 NFT 是存在于用户钱包(如 MetaMask、Coinbase Wallet 或 Ledger)中的资产。这些代币代表特定的资产和/或内容。通常,它们遵循一种代币标准 ERC-721ERC-1155 标准,这些标准规定了它们如何被铸造、转移和交互。然而,它们的功能历来只限于简单的转移和元数据更新。

什么是 ERC-6551:非同质化代币绑定账户

ERC-6551 使 Token Bound Accounts (TBAs) 成为可能。这些是具有自己地址并与特定 NFT 相关联/管理的智能合约。可以把它视为一个与 NFT 直接关联的小型钱包,开启了以下可能性:

  • NFT 可以存储资产(与你的钱包 holding assets 相比)
  • NFT 可以与其他去中心化应用(dApps)(DeFi、DAO 等)交互
  • NFT 包含自己的交易历史(与你自己的钱包历史分开)

请注意,随着 NFT 所有权的变化,其中的资产也会随之变化。

ERC-6551 用例

一些实现 ERC-6551 的想法包括:

  • DeFi:允许 NFT 直接参与收益农业或流动性提供。
  • 游戏:在游戏中,游戏内资产(NFT)可以拥有其他资产或与其他游戏内智能合约交互。
  • 市场:NFT 可以下卖单、竞拍其他资产,甚至支付平台费用。
  • DAOs:NFT 代表投票权并可以直接对提案进行投票。

现在,让我们更深入地技术性探讨构成 ERC-6551 的核心组件。

规范

下图展示了注册表、NFT、NFT 持有者和 Token Bound Accounts 之间的流向:

Graph of ERC-6551

来源

在上面的图中,用户账户 拥有 ERC-721 代币。这些 ERC-721 拥有自己的 账户(例如,Token Bound Accounts),这些账户充当可以存储其他资产的“钱包”。为了使账户进行活动,用户账户必须发起交易。账户能够执行的活动受到其实现逻辑的限制,这些逻辑存储在账户会代理的另一个智能合约中。这些账户由注册表合约创建。

现在,让我们介绍 Token Bound Accounts 的注册表和接口的具体细节。

注册表

技术上称为单例注册表的注册表,可以被视为 NFTs 及其相关联的 Token Bound Accounts 的数据库。注册表是可以部署到任何 EVM 兼容区块链的智能合约。它是无权限的、不可变的,并且没有所有者。此注册表确保所有 Token Bound Account 地址使用标准方案。

请注意,注册表已在所有主链上部署(可以在 这里 找到列表)。因此,开发者无需重新部署注册表,除非他们想要定制实现。希望在同一 NFT 之下部署多个 Token Bound Account 的开发者可以部署自己的自定义注册表合约。

单例注册表合约包含两个主要功能:

  • createAccount - 此功能为给定实现地址的 NFT 创建 Token Bound Account。此功能接受 5 个参数,分别是 implementation 地址、chainIdNFT 地址、token IDsaltinit 数据。chainId 参数允许用户在多个链上拥有持久的 Token Bound Accounts。通过这种逻辑,Token Bound Accounts 能够在需要时进行跨链通信。
  • account - 计算给定实现地址的 NFT 的 Token Bound Account 地址,给定的参数包括 implementation 地址、chainIdNFT 地址、token IDsalt

请注意,注册表要求所有 Token Bound Accounts 继承 ERC-1167 实现。

账户 & 执行接口/实施

为确保所有 Token Bound Accounts 的一致性,标准规定了所有 TBAs 必须遵循的具体接口。这些接口使 TBAs 能够可靠地运作,同时确保互操作性和可预测性。

接口要求

ERC-165 接口

这是以太坊智能合约中的标准接口检测机制。它允许智能合约发布它们实现的接口,并允许其他合约查询该接口。通过确保 TBAs 实现这个接口,我们可以在运行时可靠地确认一个合约是否支持所需的接口。

interface IERC165 {
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

ERC-1271 签名验证接口

此标准允许智能合约像常规的外部拥有账户一样验证签名。通过集成此接口,TBAs 可以有效地验证签名,并根据它们的有效性采取行动,从而实现交易或与其他合同的交互。

interface IERC1271 {
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

执行接口

此关键接口允许 TBAs 在提供了一份来自被认可的签署者的有效签名时执行任意操作。此接口的本质是允许 TBAs 代表账户执行操作。

interface IExecutionInterface {
    function execute(address to, uint256 value, bytes memory data, bytes memory signature) external returns (bool success);
}

账户实施

Token Bound Account 实现已在所有主要链上部署。如果你不需要为你的 Token Bound Account 自定义逻辑,可以使用 这里 引用的账户实现地址之一。

账户实现逻辑的核心功能是 executeowner

  • execute:该函数检查进行调用的签署者是否被授权。这是通过 _isValidSigner 函数完成的。它还检查传递的操作参数是否为 0,并发送指定数量的以太币以及函数调用。如果发生错误调用,整个交易将被撤回。
  • owner:此函数返回特定 ERC721 代币的当前所有者。
  • isValidSigner:该函数检查签署人是否为 owner 地址。
  • isValidSignature:该函数检查签名是否与 owner 的签名匹配。
  • token:此函数返回与 token bound account 关联的 ERC721 代币的详细信息。

需要注意的是:NFT 的所有者控制其相关的 Token Bound Account (TBA)。如果 NFT 被转移到其他所有者,TBA 的控制权也会随之转移,因为 TBA 永久关联于 NFT。因此,在任何时候持有或拥有 NFT 的人将控制其相关的 TBA。

代理

ERC-6551 标准还实现了可升级性(通过代理)。在智能合约和以太坊的上下文中,代理指的是一种设计模式,其中一个智能合约(代理)将所有调用推迟到逻辑合约。代理保持状态,但业务逻辑则位于逻辑合约中。使用代理模式的主要目的是为了升级。当业务逻辑需要更改或升级时,将部署一个新的逻辑合约,并将代理重定向以委托调用到这个新的逻辑合约,同时保持原有状态。

在 ERC-6551 中,这种可升级性/代理机制用于部署每个 Token Bound Account。具体来说,使用了 ERC-1167 代理的自定义版本。这允许每个 Token Bound Account (TBA) 共享相同的逻辑代码,从而节省Gas费用并简化升级。每个代理通过将其存储为 ABI 编码的常量数据附加到合约字节码中,保留唯一的状态数据(如链 id、代币合约地址和代币 ID)。

接下来,在本指南的剩余部分,我们将介绍希望创建和部署自己符合 ERC-6551 智能合约的开发者的技术步骤。

设置开发环境

创建 QuickNode 端点

为了在以太坊 Sepolia 区块链上部署我们的智能合约,我们需要访问以太坊 Sepolia 节点。为此,我们可以使用 MetaMask 中的默认 RPC 网络。然而,为了实现高达 8 倍的响应速度,我们将使用 QuickNode。创建一个免费账户,然后单击“创建一个端点”。选择 Ethereum Sepolia 链并创建你的端点。

QuickNode Endpoint

在 MetaMask 中设置 QuickNode RPC

创建你的以太坊 Sepolia 端点后,复制你的 HTTP Provider 端点,并导航到你的 MetaMask 钱包。在你的钱包主页上,单击左上角的网络选项卡,然后单击“添加网络”。MetaMask 将在新选项卡中以全屏模式打开。

在网络列表的底部找到“手动添加网络”按钮。然后,按以下方式完成各项字段:

  • 网络名称:QuickNode Sepolia
  • 新 RPC URL:YOUR QUICKNODE HTTP PROVIDER ENDPOINT URL
  • 链 ID:11155111
  • 货币符号:ETH
  • 区块浏览器 URL(可选):https://sepolia.etherscan.io/

然后单击“保存”以添加自定义网络。

使用 QuickNode 的多链水龙头为你的钱包提供资金

现在我们已经在 MetaMask 中配置了 QuickNode 端点,下一步是检索一些测网 ETH 以支付交易费用。

导航至 QuickNode 多链水龙头,连接你的钱包,并请求 Sepolia 测试网上的 ETH。

注意:你至少需要在主网上有 0.001 ETH 的余额,才能有资格使用水龙头。

QuickNode Multi-Chain Faucet

在我们的钱包获得资金并设置自定义 RPC 后,让我们进入代码部分。

克隆代码库

我们将使用 Hardhat,一个智能合约开发工具包,以及 OpenZeppelin,一个经过审计的智能合约库,来创建智能合约。

打开终端窗口并克隆以下 GitHub 仓库:

https://github.com/quiknode-labs/qn-guide-examples

导航到 ethereum 下的 erc-6551 目录:

cd ethereum/erc-6551

然后运行以下命令导航到你的代码库并安装依赖项:

npm install

我们还创建一个 .env 文件,用于保存我们的私钥以进行交易。

echo > .env

.env 文件中,复制以下变量并输入你的 RPC URL 和私钥凭据。要从你的 MetaMask 钱包提取私钥,请按照本 指南 操作。

RPC_URL=
PRIVATE_KEY=

记得保存文件!

现在,随着我们的开发环境设置完成,我们可以进入通过注册表合约创建 Token Bound Account 的步骤。

创建 Token Bound Account (TBA)

由于 ERC-6551 要求与其关联一个 ERC-721 代币,因此我们还需要部署一个。请不用担心。我们在你克隆的 GitHub 仓库中已包含一个合约;然而,为了将来参考,你也可以查看此 QuickNode 指南 - 如何创建和部署一个 ERC-721 (NFT)

现在,在项目的主目录中,在终端运行以下命令:

npx hardhat run --network sepolia scripts/createAccount.js

上述脚本中主要的组件以下代码:

// 创建注册表合约的实例
const RegistryContract = await hre.ethers.getContractAt('ERC6551Registry', registryAddress, signer);
...
// 部署并铸造我们稍后将转移到 TBA 的 NFT
const nftTokenContract = await hre.ethers.deployContract('MyToken', signer);
...
const mintTxn = await nftTokenContract.safeMint(signer.address);
...
// 调用注册表上的 createAccount 函数,创建我们的 TBA 地址
const transaction = await RegistryContract.createAccount(implementationAddress, chainId, nftTokenContract.target, tokenId, salt, initData);

有关完整代码,请参考 GitHub 仓库

一旦挖矿,你将会在控制台中看到类似以下的输出:

正在部署合约...
ERC-721 合约部署到 0x8953A287122c2f76d077A94E9E007ABACF87B7C7
铸造成功: 0x49c157ab9b8fbd2e6fc2aaf8ef429b55d421e6605adf329f1ac7cc53a1f79a56
createAccount 调用成功。交易哈希: 0xb8847e5a6d1687bad38f1303c31ef707a700714a45d6d785e061c6130cf800ac
Token Bound Account:  0xB992415D3BC7b19323bfE84c1A033303Ffe60E37

通过上述脚本,我们首先部署了一个 ERC-721 合约,然后从中铸造了一个 NFT。接着,我们在注册表合约上调用了 createAccount 函数以生成我们的 Token Bound Account (TBA)。请记住,注册表合约已经在多个 EVM 上部署,因此除非你需要自己的私有或自定义实现,否则可以与主注册表合约交互。

你现在拥有一个可以与区块链互动并拥有资产的 Token Bound Account。请查看 Etherscan 验证交易是否已确认(这是一个 示例交易)。如果你导航到 日志 选项卡,你将看到 AccountCreation 事件显示 Token Bound Account 地址(例如,account)。

Etherscan Logs

在下一部分中,我们将介绍如何与新创建的 Token Bound Account 进行交互。

与你部署的 Token Bound Account (TBA) 进行交互

随着我们的 NFT 和 Token Bound Account 创建完成,让我们从个人钱包向 Token Bound Account 合约发起转移我们铸造的 NFT。

打开 interactAccount.js 文件并填写 nftContractAddress(例如,ERC-721 合约)和 tokenBoundAccountAddress 变量的正确值。这些值在上一个脚本的终端中已记录。完成后,保存文件。

现在,运行以下 interactAccount.js 脚本,向你的 Token Bound Account 发送 ETH(用于Gas费用),然后将 NFT 从你的钱包转移到你的 Token Bound Account。

npx hardhat run --network sepolia scripts/interactAccount.js

上述脚本中主要的组件以下代码:

// 通过调用注册表合约的 account 函数计算 TBA 地址
ERC6551Registry.account(accountImplementationAddress, chainId, nftContractAddress, tokenId, salt);
...
// 向 TBA 地址发送资金,并记录转移前后的余额
sendFundsToTokenAccount()
...
// 批准,然后将铸造的 NFT 从我们的个人钱包转移到 TBA 地址
transferToken()

有关完整代码,请参考 GitHub 仓库

你应该看到如下输出:

Token Bound Account Address: 0xd42d61CFDfce1557d02bA6CE83Dc2583586A4c12
Token account has 0 ETH before transfer
Token account has .01 ETH after transfer
当前 tokenId 0 的所有者是 0x351132C80b1e1De690A6dAe996649E0b2a1E7888
批准交易成功。哈希: 0x426fa733d960a8f02e3291a6d318417d5de003e7f59ba466b9da526c11e53491
转移交易成功。哈希: 0x2b328af9eb0415801f57967ab541e6b0089ada2d549e5b232a0e25585ea0e981
tokenId 0 的新所有者是 0xd42d61CFDfce1577d02bB5CE83Dc2583586A4c12

发生了什么?回顾一下,在此脚本中,我们:

  • 通过调用注册表合约的 account 函数计算了 TBA 地址
  • 通过从个人钱包向其转移 .01 ETH 为 TBA 进行资金补充
  • 在 NFT 上调用了 approve 函数,批准从我们个人钱包转移到 TBA 地址
  • 将 NFT 转移到 TBA

在脚本的执行过程中,我们记录了数据点以确保余额正确。

在 Etherscan 上检查我们的 TBA 后,我们可以确认 NFT(例如,MyToken)现已在我们的 TBA 中:

Etherscan balance TBA

接下来是什么?通过你学到的知识,你可以尝试与你的 Token Bound Account 交互,将 NFT 转移到另一个地址。

测试你的知识

通过你在本指南中所做的一切,让我们测试一下你的知识。尝试完成以下简短测验!

🧠知识测试

在单例注册表合约中,createAccount 函数的作用是什么?

更新代币元数据 转移 NFT 的所有权 创建 NFT 的 Token Bound Account 验证 NFT 签名

结束

到这里为止!到目前为止,你已经了解了更多关于 ERC-6551 的内容以及如何实现它。如果你有任何问题,请随时使用我们在 Discord 上的专用频道或通过下面的表单提供反馈。通过关注我们的 TwitterTelegram 公告频道,保持与最新动态的同步。

我们 ❤️ 反馈!

让我们知道 如果你有任何反馈或新主题的请求。我们非常乐意倾听你的意见。

  • 原文链接: quicknode.com/guides/eth...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。