在 Starknet 上编写和部署你的第一个 NFT

我们的使命是将开发人员带入 Starknet 生态系统。为实现这一目标,我们正在制作一个内容系列,该系列将通过在网络上构建的基础知识来教育和指导您

了解如何构建您的第一个 Cairo 智能合约!

在 Starknet 上编写和部署你的第一个 NFT

我们的使命是将开发人员带入 Starknet 生态系统。为实现这一目标,我们正在制作一个内容系列,该系列将通过在网络上构建的基础知识来教育和指导您。 

之前,我们解释了什么是 ERC20 代币以及如何在 Starknet 上创建和部署 ERC20 代币。本周,我们将重点关注 ERC721 代币,也称为 NFT。 

到本文结束时,您将了解什么是 ERC721 令牌以及如何使用 OpenZeppelin 的库创建一个。

WTF 是 NFT 吗?

NFT(不可替代代币)是存在于区块链上的独特数字资产,例如 Starknet。 

这些代币通常被称为 NFT,与它们的对应代币(可替代代币)不同,因为它们不能与其他代币等价交换或交易。

与可替代的 ERC20 令牌不同,这意味着它们可以用相同的令牌替换,类似于金钱的运作方式。NFT 是不可替代的,这意味着它们不能被替换,因为每个 NFT 都有一个独特的标识符和元数据,将它们与其他代币区分开来。

ERC721标准

ERC721 标准由 William Entriken、Dieter Shirley、Jacob Evans 和 Nastassia Sachs 提出,并受到 ERC20 标准的启发,包含类似 ERC20 的方法,例如:

  • 名称:此函数定义令牌的名称。
  • 符号:此函数定义令牌的符号。
  • balanceOf:此函数返回一个地址拥有的 NFT 数量。

ERC721标准还引入了一些新方法:

  • ownerOf:此函数返回令牌所有者的地址。
  • supportsInterface:此函数查询合约是否实现接口。
  • transferFrom:将令牌所有权从一个帐户转移到另一个帐户。
  • safeTransferFrom:将令牌所有权从一个帐户安全转移到另一个帐户。安全传输意味着它检查接收者是否有效。它还可以接受发送给接收器的附加数据。
  • 批准:此功能授予或批准另一个实体代表所有者转移令牌的权限。
  • setApprovalForAll:此函数启用或禁用操作员管理所有所有者资产的批准。
  • getApproved:此函数获取特定令牌 ID 的批准地址。
  • isApprovedForAll:此函数查询一个地址是否是另一个地址的授权操作员。

设置原星环境

要开始在 Starknet 上构建你的第一个 NFT,你需要设置你的开发者框架。我们的首选是 Protostar。 

如果您不熟悉开发环境或想了解有关 Protostar 的更多信息,我们推荐我们关于创建Cairo 开发环境的文章。 

设置好 Protostar 后,您就可以构建您的第一个Starknet NFT了。我们称我们的项目为“ argentERC721 ”。 

为此,请运行:

原星初始化

将进一步请求项目名称和库的目录名称。这是成功初始化项目所必需的。

创建一个新文件

我们需要在我们的src文件夹中创建一个名为ERC721.cairo的新文件。这是我们要编写合约代码的地方。构建 ERC721 令牌

进口

在我们的新文件中,我们将从%lang starknet指令开始,该指令指定我们的文件包含 Starknet 合约的代码。

完成后,我们导入所有必要的库函数。 

%lang starknet

from starkware.cairo.common.cairo_builtins import HashBuiltin

from starkware.cairo.common.uint256 import Uint256

from starkware.starknet.common.syscalls import get_caller_address

from cairo_contracts.src.openzeppelin.token.erc721.library import ERC721

from cairo_contracts.src.openzeppelin.introspection.erc165.library import ERC165

from cairo_contracts.src.openzeppelin.access.ownable.library import Ownable

从此代码片段中,您可以看到我们从Openzeppelin 的 ERC721 库中导入并将使用ERC721ERC165命名空间。我们还导入了pedersen哈希相关操作所需的 HashBuiltin,用于创建 Uint256 变量的 Uint256 结构,以及用于获取调用者地址的get_caller_address 。

ERC721 合约接口

这是 ERC721 合约接口,它公开了我们在构建令牌时需要实现的方法:

%lang starknet

from starkware.cairo.common.uint256 import Uint256

@contract_interface

namespace IERC721 {

   func name() -> (name: felt) {

   }

   func symbol() -> (symbol: felt) {

   }

   func balanceOf(owner: felt) -> (balance: Uint256) {

   }

   func ownerOf(tokenId: Uint256) -> (owner: felt) {

   }

   func safeTransferFrom(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*) {

   }

   func transferFrom(from_: felt, to: felt, tokenId: Uint256) {

   }

   func approve(approved: felt, tokenId: Uint256) {

   }

   func setApprovalForAll(operator: felt, approved: felt) {

   }

   func getApproved(tokenId: Uint256) -> (approved: felt) {

   }

   func isApprovedForAll(owner: felt, operator: felt) -> (isApproved: felt) {

   }

   func mint(to: felt) {

   }

} 

写合同

构造器

对于我们的 ERC721 令牌,我们需要在部署时初始化某些变量,例如namesymbolowner。为此,我们的合约必须实现一个构造函数:

@constructor

func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (

   name: felt, symbol: felt, owner: felt

) {

   ERC721.initializer(name, symbol);

   Ownable.initializer(owner);

   return ();

}

我们还通过使用从 Openzeppelin 导入的ERC721命名空间调用初始化器内部函数,同时传递所需的函数参数 [名称和符号]。我们最终通过调用Ownable命名空间的初始化函数为合约分配所有者。

支持界面

此函数查询以检查合约是否实现了某个接口。

@view

func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (

   interfaceId: felt

) -> (success: felt) {

   let (success) = ERC165.supports_interface(interfaceId);

   return (success,);

}

姓名

name 函数是一个视图函数,它在查询时简单地返回令牌的名称。

@view

func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} () -> (name: felt) {

   let (name) = ERC721.name();

   return (name,);

}

象征

symbol 函数在查询时返回令牌的符号。

@view

func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} () -> (symbol: felt) {

   let (symbol) = ERC721.symbol();

   return (symbol,);

}

余额

函数的余额返回一个地址拥有的 NFT 数量。

@view

func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (owner: felt) -> (balance: Uint256) {

   let (balance: Uint256) = ERC721.balance_of(owner);

   return (balance,);

}

所有者

此函数返回令牌所有者的地址。

@view

func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (tokenId: Uint256) -> (owner: felt) {

   let (owner) = ERC721.owner_of(tokenId);

   return (owner,);

}

获得批准

此函数获取特定令牌 ID 的批准地址。

@view

func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (tokenId: Uint256) -> (approved: felt) {

   let (approved) = ERC721.get_approved(tokenId);

   return (approved,);

}

为所有人批准

此函数查询一个地址是否是另一个地址的授权操作员。

@view

func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr} (owner: felt, operator: felt) -> (isApproved: felt) {

   let (isApproved) = ERC721.is_approved_for_all(owner, operator);

   return (isApproved,);

}

转移

此功能将令牌所有权从一个帐户转移到另一个帐户。

@external

func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

   _from: felt, to: felt, tokenId: Uint256

) {

   ERC721.transfer_from(_from, to, tokenId);

   return ();

}

安全转移自

将令牌所有权从一个帐户安全转移到另一个帐户。

@external

func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

   _from: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*

) {

   ERC721.safe_transfer_from(_from, to, tokenId, data_len, data);

   return ();

}

批准

此功能授予或批准另一个实体代表所有者转移令牌的权限。

@external

func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

   account: felt, tokenId: Uint256

) {

   ERC721.approve(account, tokenId);

   return ();

}

为所有人设置批准

此功能启用或禁用批准操作员管理所有所有者的资产。

@external

func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

   operator: felt, approved: felt

) {

   ERC721.set_approval_for_all(operator, approved);

   return ();

}

恭喜,您刚刚完成了第一个 ERC721 合约!您可以在此处找到完整的合同代码。

铸造 NFT

当我们完成我们的 NFT 合约时,我们需要一个额外的功能来为用户铸造具有不同代币 ID 的新代币。为此,我们将实现一个存储变量 token_counter 和一个外部函数 mint。

令牌计数器

token_counter 是一个存储变量,它跟踪创建的令牌数量以确定下一个令牌 ID。

@storage_var

 func token_counter() -> (id: felt) {

}

mint

mint 函数是一个实现铸币逻辑的外部函数。它首先检查调用者是合约所有者,然后计算新的代币 ID,将新代币铸造给接收者,最后更新 token_counter 变量。

@external

func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(

   to: felt

) {

   Ownable.assert_only_owner();

   let (prevTokenId) = token_counter.read();

   let tokenId = prevTokenId + 1;

   ERC721._mint(to, Uint256(tokenId, 0));

   token_counter.write(tokenId);

   return ();

}

部署

最后,按照部署合约的常规步骤,我们将首先构建/编译、声明和部署。

建筑

当你构建你的 Starknet NFT 时,你需要在你的 protostar.toml 中指定你的合约的正确路径,并使 Protostar 能够找到你的 lib 文件夹,其中包含你的 Openzeppelin 合约。为此,请添加代码段:

cairo-path = ["lib"]

Your protostar.toml file should look like this:

[project]

protostar-version = "0.9.1"

lib-path = "lib"

cairo-path = ["lib"]

[contracts]

ERC721 = ["src/ERC721.cairo"]

要构建你的合约,只需运行以下命令:

原星建造

构建您的 ERC721 合约

宣告

在执行“declare”命令之前,您需要在文件或终端中设置与指定账户地址关联的私钥。 

要在终端中设置您的私钥,请运行以下命令:

export PROTOSTAR_ACCOUNT_PRIVATE_KEY=[你的私钥在这里]

不要与任何人分享您的私钥。甚至不是银色。它应该只供您使用。

要声明您的合约,只需运行以下命令:

protostar declare ./build/ERC721.json --network testnet --account 0x0691622bBFD29e835bA4004e7425A4e9630840EbD11c5269DE51C16774585b16 --max-fee auto

声明您的 ERC721 Starknet 合约

部署中

最后,我们需要调用传入合约类哈希的“deploy”命令来部署我们的合约。

protostar deploy 0x04dae654c7b6707667a178729b512d61494fe590ab4accc46923d6409b97e617 --network testnet --account 0x0691622bBFD29e835bA4004e7425A4e9630840EbD11c5269DE51C16774585b16 --max-fee auto --inputs 71959616777844 4280903 0x0691622bBFD29e835bA4004e7425A4e9630840EbD11c5269DE51C16774585b16

部署您的 ERC721 Starknet 合约

结论

恭喜!您刚刚在 StarkNet 上编写并部署了您的第一个 ERC721 合约。

要与已部署的合约进行交互,请在此处检查 Starkscan 。

如果您对此有任何疑问,请联系我@0xdarlington,我很乐意帮助您使用 Argent X 在 StarkNet 上进行构建。

如需更多开发人员资源,请关注我们的社交网站:

推特——  @argentHq

工程 Twitter —  @argentDeveloper

领英——  @argentHq

Youtube——  @argentHQ

英文原文链接:https://www.argent.xyz/blog/writing-and-deploying-your-first-nft-on-starknet/

所有文章项目介绍

Shardeum Betanet 发布

2023-2-1 11:40:00

所有文章项目介绍

Index Coop 引入多元化质押

2023-2-8 12:57:00

搜索