在本教程中,我们将通过构建 NFT 市场的初始框架,让您体验 StarkNet 的一些功能,首先构建一个使用 StarkNet.js SDK 与 ERC721 合约交互的基本应用程序。未来的帖子将更详细地介绍与 Cairo 一起开发自定义智能合约以及使用 MetaMask Flask(安装了 starknet-snap)构建 dapp。
在我们深入研究之前,先了解一些背景知识。StarkNet 是一种无需许可的去中心化有效性汇总(也称为“ZK-Rollup”)。它作为以太坊上的 L2 网络运行,使任何 dapp 能够在不影响以太坊的可组合性和安全性的情况下实现无限规模的计算,这要归功于 StarkNet 对最安全和可扩展性的加密证明系统之一 - STARK 的依赖。
ConsenSys 和 StarkNet 在今年年初合作,通过将这种安全和高性能的技术集成到 Infura 中并使其与 MetaMask 兼容,将其带入 Web3 社区。
Infura 提供标准 JSON-RPC 端点,通过 Equilibrium 构建的 Pathfinder 客户端以直接的方式与 StarkNet 网络无缝通信。
StarkNet API 映射了以太坊 JSON-RPC 方法的子集(有一些细微差别),因此精通 eth_
的用户可以轻松地将带有eth_ 前缀的调用替换为 starknet_并立即与 starknet_
节点或合约进行交互。
虽然 StarkNet 合约是用 Cairo 编写的,这是一种与 Solidity 不同的图灵完备的高级语言和框架,但用户无需具备这些知识即可成功完成以下教程。
对我们来说幸运的是,Web3 社区(尤其是 OpenZeppelin 团队)已经为最常见的 ERC 标准创建了一些现成的预设。在本教程中,我们将使用 OpenZeppelin Cairo 合约,具体来说:
- 帐户(🧐 让我们在下一章中拆封)
- ERC721EnumerableMintableBurnable
本教程中使用的 OpenZeppelin Cairo 合约版本是 0.3.1。
我们将提供已经编译好的合约文件,其中包含所有方法和结构 (ABI) 的定义,准备好部署在 StarkNet 网络上。
使用StarkNet.js SDK的基本应用程序
前提条件在开始之前,请确保你拥有:
- 一个Infura账户
- 安装了node&npm(在本指南中→v16.xx.x)
- 对ERC721标准有基本了解
- 你喜爱的IDE
入门
我们将首先创建一个启用 StarkNet 端点的新 Infura Web3 访问密钥(以前是项目 ID),以及一个用于存储 NFT 艺术品的 IPFS 访问密钥。我们的应用程序将使用这两个密钥对 StarkNet 网络执行交易,并检索有关帐户余额和 NFT 集合的有用信息。
使用 StarkNet 端点创建新的 Web3 访问密钥要访问 StarkNet 网络,我们需要有一个端点,我们所有来自/到 StarkNet 节点的请求都将通过该端点执行。让我们看看如何使用 Infura 做到这一点(或遵循此入门指南)。
- 登录 Infura 主页
- 单击右侧的按钮 - 创建新密钥
- 从弹出的模式中:
- 选择网络 → Web3 API
- 在名称处输入自己想要显示的内容🙂
- 点击“创建”
- 向下滚动,直到您发现 StarkNet
- 从网络下拉列表中,选择 Goerli 测试网端点
- 点击右侧图标复制内容
输出结果应该是:https://starknet-goerli.infura.io/v3/<API_KEY>注意,这将在本教程中很有用的。
创建一个新的IPFS访问密钥和网关
区块链上的存储成本很高,这就是为什么在链下存储 NFT 媒体是一种常见做法。IPFS 通常是许多开发人员的首选,主要有三个原因:它是免费的*,它是去中心化的,它可以保证对资源的访问非常长的时间。
我们将需要在Infura上创建一个新的IPFS访问密钥,并稍后设置一个我们将使用的专用网关。
- 登录到Infura的主页面
- 点击右侧的按钮--创建新密钥
- 在弹出的模式中:选择网络→IPFS在名称处输入自己想要显示的内容
- 点击 "创建"。
- 在 "专用网关 "部分,拨动按钮以启用它
- 插入一个你喜欢的子域名称
- 复制并保存网关的URL
- 复制并保存项目ID和API密钥秘密
- 现在你可以开始建构了
建构
让我们首先检查所有依赖项是否已正确安装。
本教程的代码已经使用以下工具版本进行了测试:
-
节点 → 16.17.0
-
Npm → 8.18.0
其他版本可能有效,但建议您使用主要版本以获得完全兼容性。(提示:想在不同节点版本之间快速切换?试试nvm!)
一切就绪! 现在让我们创建一个新的 Node 项目。
最后一条命令将运行 npm CLI 工具并创建一个新的 package.json
。
StarkNet.js
Starknet.js是与StarkNet互动的官方Javascript库(SDK),由一个独立的贡献者社区维护。本教程中使用的StarkNet.js版本是4.6.0。
Starknet.js 可以通过运行以下npm命令作为标准的node模块进行安装
我们还需要将"type": "module""
到我们的package.json
中,以启用 ES-module 并能够使用import
一旦安装完成,你现在应该有一个package.json
文件,看起来像这样:
现在是时候让我们掌握代码了🧑💻
在StarkNet上部署一个新账户
在StarkNet 中,账户模型与基于EVM的区块链上的模型不同。这是一个更灵活的模式,也是以太坊社区期待已久的模式。
在这里,用户账户的概念变成了一个contract_address
;StarkNet用户将公开分享该地址,以便有人可以向其发送代币,而不是直接从用户的私钥/公钥对中得出的传统公共地址。该合同可以包含任何代码,而用户仍然通过用其私钥签署交易来与之互动。
换句话说,StarkNet 区分了用户钱包和用户账户的概念。
此外,可以说用户账户只是一种特殊类型的 Cairo 合约,只要它包含必要的逻辑来转发用有效私钥签署的交易。
在你喜欢的 IDE 中打开该项目,并创建一个新的index.js
文件。
初始化一个新的提供者提供者
API 允许你与 StarkNet 网络进行交互,而无需签署交易或消息。
下载账户合约ABI
如上所述,StarkNet 合约是在Cairo 编写的。但是,为了使本教程保持超级简单,我们提供了等效的已编译合约版本,其中包含 JSON 格式的 ABI。
这些已编译的合约可以在以下存储库中找到。
跳转到该页面并将 OZAccount.json
文件下载到位于项目根目录的新contracts
目录中。您的目录树应如下所示:
阅读编译的账户合约
请注意,本教程中用于解析已编译合约的 json
模块是 starknet
包的一部分,它提供了标准 json
节点模块的自定义实现。
生成私钥和公钥
对使用stark
模块,我们生成将用于签署和执行交易的私钥和公钥对。
如上所述,在 StarkNet 中,账户地址被计算为与控制账户的密钥没有直接关系的智能合约,这就是我们无法从这些密钥中派生账户地址的原因,相反,我们将要求 创建一个的附加步骤。
记下这两个键,因为我们可能希望稍后重用它们以进行进一步的操作。请注意将您的私钥存储在安全的地方,切勿与任何人共享。
将新帐户部署为合约我们可以使用 deployContract
提供者方法将预编译的账户合约部署到 StarkNet,并传入之前生成的公钥输入。
此操作可能需要几分钟(约 10 分钟)才能完成🙂
您可以通过 StarkNet 区块浏览器 (Voyager 随时关注交易状态:
最后,让我们创建一个新的Account
对象,我们将在本指南中进一步使用它。Account 扩展了 Provider
并继承了它的所有方法。它还引入了允许帐户使用自定义Signer
创建和验证签名的新方法。此 API 是与 StarkNet 上的 Account 合约交互的主要方式。
综合起来,我们的 index.js 应该是这样的:
提示:此代码段可以直接执行。但是,为了在运行后续代码部分时节省一些时间,您可以将私钥的随机生成替换为第一次运行的输出。这将重复使用相同的密钥对,而无需部署新帐户。const privateKey = <PRIVATE_KEY>;
ERC721 NFT 合约
如上所述,在本教程中,我们将使用基于 ERC721 标准的 OpenZeppelin implementation 的 ERC721EnumerableMintableBurnable
合约。
下载 ERC721 合约 ABI
将 ERC721EnumerableMintableBurnable.json
文件从以下存储库下载到位于项目根目录的 contracts
目录中。现在你的目录树应该是这样的:
阅读编译后的 ERC721 合约
请注意,本教程中用于解析已编译合约的 json
模块是starknet
包的一部分,它提供了标准json
节点模块的自定义实现。
为账户注资
为了在 StarkNet 网络上执行交易(就像在以太坊上一样),我们需要用 gas 填充。可以使用官方的 StarkNet Goerli Faucet 手动为帐户注资。但是,由于我们的代码一旦启动就不会停止,并且交易需要一些时间来确认,所以我们需要添加一小段代码来暂停执行并在所有这些操作完成后重新启动它。
因此,我们将在 index.js
中添加以下函数:
让我们在部署之前调用这个方法。
部署 ERC721
合约一旦我们完成了资金操作并且接收账户更新了新的余额,我们就可以部署 ERC721 NFT 合约了。
一旦交易被确认,我们可以打印合约地址并在区块浏览器上进行可视化。
将账户连接到 NFT 合约
合约可以基于 ABI 在 JavaScript 中进行数据转换。他们也可以通过提供的 Signer 对StarkNet 进行调用。
通过将账户连接到Contract
,我们隐含地定义了谁将与网络交互并使用他们的私钥签署交易。
铸造一个 NFT
终于到了本教程中最激动人心的部分:制作我们的第一个Stark-web3 数字艺术。👨🎨 mint
交易,按照标准定义,将采取收件人的账户地址和令牌ID,作为铸币NFT的输入。合同API允许我们直接使用 <Contract>.mint
接口,因为这个方法在erc721
ABI中定义。
将所有线缝合在一起:
用户可能已经注意到本教程中的一些“有趣”的类型转换。我们不能像在 Solidity 中那样简单地传递 uint256
的原因是,在Cairo,只有一种数据类型称为felt
,代表字段元素。简单来说,它是一个最多 76 位小数的无符号整数,但它也可以用来存储地址。别担心,这不是本教程的一部分,但值得一提。🙂
将NFT数据上传到 IPFS
在本节中,我们将使用之前在 Infura 上设置的 IPFS 网关来上传我们的 NFT 媒体和元数据。首先,我们需要安装 IPFS 客户端包。npm install --save ipfs-http-client
初始化 IPFS 客户端现在是时候回忆一下我们之前记下的信息了,即:
-
INFURA_IPFS_PROJECT_ID
-
INFURA_IPFS_SECRET
-
INFURA_IPFS_GATEWAY
然后您将它们放在我们的代码中,如下所示:
此代码段将使用我们的个人 Infura 信息创建 IPFS 网关的实例。
请注意,您始终可以将imageUrl
替换为您喜欢的任何内容!
将媒体上传到 IPFS
首先,我们将通过直接从网络上获取来上传 NFT 媒体。
将 NFT 元数据上传到 IPFS
一旦我们完成了媒体的上传,我们可以将一些基本信息附加到我们的 NFT,例如名称、描述和图像的 URI——通常称为元数据。
设置 NFT tokenURI
我们将调用 ERC721 标准方法setTokenURI
来更新与我们的 NFT 相关的信息。但是,在此之前,我们需要执行一个小动作🪄。如上所述,Cairo 仅使用一种数据类型,在将string
转换为felt
时,我们需要确保该值不高于 31 个字符。由于 IPFS URI 可能与此标准不匹配,因此我们需要一种解决方法来“缩短”此文本。实现这一目标的最快速和最简单的方法是使用网上提供的免费URL缩短器。在本教程中,我们将使用tinyurl.com。
我们将调用 tinyurl.com API 以从我们的 Infura IPFS URI 开始创建一个新的短 url。让我们将此代码段添加到我们的代码库中。
http
包已经是 node 的一部分,因此,我们不需要安装任何新的依赖项
然后,让我们在元数据上传后立即调用这个方法。
🧙🏼♀️现在,一切都准备好了,我们可以执行交易。
检索NFT元数据信息
最后,我们将通过调用标准 ERC721 方法 tokenURI
来检索NFT元数据。
把这一切结合起来:
恭喜你,你成功了! 👏你在 StarkNet 上用Infura铸造了一个NFT。🥳
你可以在这里找到本教程的完整代码:https://github.com/czar0/my-starknft-world.
资源
想更深入地了解StarkNet的世界,这里有一些资源供你使用。
-
StarkNet documentation
-
StarkNet.js documentation
-
OpenZeppelin Account Cairo contract documentation
-
OpenZeppelin ERC721 Cairo contract documentation