在 Starknet 上编写和部署您的第一个 ERC20 代币

本文是我们正在努力帮助将开发人员带入 Starknet 生态系统的扩展内容系列的一部分。 之前,我们解释了如何使用 Protostar、Argent X 和 StarkScan 创建终极 Cairo 开发环境。 设置完成后,您就可以编写您的第一个 ERC20 代币并将其部署到 Starknet! 到本文结束时,您将了解什么是 ERC20 令牌以及如何使用 OpenZeppelin 的库创建一个。

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

在 Starknet 上编写和部署您的第一个 ERC20 代币

本文是我们正在努力帮助将开发人员带入 Starknet 生态系统的扩展内容系列的一部分。

之前,我们解释了如何使用 Protostar、Argent X 和 StarkScan 创建终极 Cairo 开发环境。

设置完成后,您就可以编写您的第一个 ERC20 代币并将其部署到 Starknet!

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

WTF 是 ERC20 代币吗? 

ERC20 代币是可替代的,这意味着它们可以被另一个代币替换。这就是金钱的运作方式。一个钱包中的 20 美元钞票具有相同的价值,并且可以以与不同的 20 美元钞票相同的方式使用。

Fabian Vogelsteller 和 Vitalik Buterin 提出了 ERC20 标准,以创建一套可替代代币的通用标准。在 ERC20 标准之前,以太坊上的每个代币都是不同的,这意味着钱包必须编写自定义代码来支持它们。 

ERC20包括以下主要方法:

  1. name() -> (name: felt)  — 返回令牌的名称
  2. symbol() -> (symbol: felt)  — 返回代币的符号
  3. decimals() -> (decimals: felt)  — 返回令牌的小数
  4. totalSupply() -> (totalSupply: Uint256)  — 返回代币的总供应量。
  5. balanceOf(account: felt) -> (balance: Uint256)  — 查询并返回特定账户的余额。
  6. allowance(owner: felt, spender: felt) -> (remaining: Uint256)  — 查询并返回所有者分配给支出者的津贴。
  7. transfer(recipient: felt, amount: Uint256) -> (success: felt)  — 将一定数量的代币从发送者转移到指定的接收者。
  8. transferFrom(sender: felt, recipient: felt, amount: Uint256) -> (success: felt)  — 允许花费者将允许所有者/发送者花费的一定数量的代币转移给指定的接收者。
  9. approve(spender: felt, amount: Uint256) -> (success: felt)  — 批准消费者从所有者的钱包中花费一定数量的代币。

设置原星环境

现在我们熟悉了什么是 ERC20 令牌,我们可以开始编写和部署 ERC20 令牌。 

您需要安装 Protostar。如果您没有安装 Protostar,或者您想了解更多相关信息,我们推荐您关于创建Cairo 开发环境的文章,因为它对于在 Starknet 上构建至关重要。

准备就绪后,我们将需要初始化一个新项目。让我们称我们的项目为“ argentERC20 ”。

为此,请运行:

原星初始化

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

创建一个新文件

我们将在我们的src文件夹中创建一个名为ERC20.cairo的新文件。这是我们将编写合约代码的地方。创建一个名为的新文件

进口

在我们的新文件中,我们将首先指定%lang starknet指令以指定我们的文件包含 Starknet 合约的代码,类似于我们为 solidity 合约执行pragma solidity 的方式。

然后,我们将导入我们需要在合约中使用的所有必要的库函数。

%lang 星网

从 starkware.cairo.common.cairo_builtins 导入 HashBuiltin

从 starkware.cairo.common.uint256 导入 Uint256

从 starkware.cairo.common.bool 导入 TRUE

从 cairo_contracts.src.openzeppelin.token.erc20.library 导入 ERC20

从上面的代码片段可以看出,我们首先从 Starkware 官方的 cairo-lang 库中导入HashBuiltinUint256TRUE函数,然后从Openzeppelin 的 ERC20 库中导入ERC20命名空间。

导入 HashBuiltin是因为 Pedersen 哈希相关操作需要它,UINT256提供了一种从两个 felt 创建 Uint256 结构的方法,TRUE是 1 的布尔表示。 

最后,我们导入ERC20命名空间,这使得我们的合约可以访问 Openzeppelin 的所有内部功能。

Openzeppelin 库

我们在本文中多次提到了 Openzeppelin 库,但是如果您是智能合约开发的新手,您可能想知道 Openzeppelin 库是什么。

Openzeppelin 的库是用于以太坊、Starknet 和其他网络的模块化、可重用、安全的智能合约的集合,以各自的语言编写。 

感谢 Openzeppelin 团队的辛勤工作,我们现在可以通过简单地在自定义合约中导入和使用他们的库来轻松构建 ERC20 代币。

ERC20 代币接口

接口是没有实现的合约函数定义的列表。它有助于描述合约的功能,主要用于从外部调用合约。 

我们将查看 ERC20 令牌的接口,以进一步了解我们在构建令牌时需要实施的方法:

%lang 星网

从 starkware.cairo.common.uint256 导入 Uint256

@contract_interface

命名空间 IERC20 {

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

   }

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

   }

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

   }

   func totalSupply() -> (totalSupply: Uint256) {

   }

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

   }

   func allowance(owner: felt, spender: felt) -> (remaining: Uint256) {

   }

   func transfer(recipient: felt, amount: Uint256) -> (success: felt) {

   }

   func transferFrom(发件人:感觉,收件人:感觉,金额:Uint256)->(成功:感觉){

   }

   func approve(spender: felt, amount: Uint256) -> (success: felt) {

   }

}

构造函数逻辑

构造函数主要用于在合约部署时初始化某些状态变量。 

要在 Cairo 中创建构造函数,您需要使用@constructor装饰器。

对于我们的 ERC20 代币,我们希望在部署时初始化变量,例如namesymboldecimalstotalSupply。 

为此,我们的合约必须实现以下构造函数:

@构造函数

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

   _name: felt, _symbol: felt, _decimals: felt, initialSupply: Uint256, recipient: felt

){

   ERC20.initializer(_name, _symbol, _decimals);

   ERC20._mint(收件人,初始供应);

   返回 ();

}

如上面的代码片段所示,我们的构造函数必须命名为constructor并接受 5 个参数 [_name, _symbol, _decimals, initialSupply, recipient]。

我们还通过使用从 Openzeppelin 导入的ERC20命名空间调用初始化器内部函数,同时传递所需的函数参数 [名称、符号和小数]。初始化函数创建/实例化一个总供应量为 0 的新 ERC20 代币。

为了在部署时创建固定的总供应量,我们调用传入函数参数 [recipient, initialSupply]的_mint函数。_mint函数铸造提供给收件人地址的 initialSupply。

在开罗的功能

实现我们的构造函数逻辑后,我们现在可以实现我们的代币符合 ERC20 标准所需的其他功能,但在我们继续之前,让我们拿出几行来区分 Cairo 中的两种主要类型的功能。

  1. 外部函数——外部函数是改变区块链状态的函数,是使用@external装饰器创建的。
  2. 视图函数——视图函数是 getter 函数。它们不会改变区块链的状态,并且是使用@view装饰器创建的

实现其他功能

1.姓名

name 函数是一个视图函数,它在查询时简单地返回令牌的名称。在函数的逻辑中,我们只是使用ERC20命名空间调用Openzeppelin 合约中的name方法,然后返回我们得到的结果。

@看法

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

   let (name) = ERC20.name();

   返回(名称,);

}

2.符号

symbol 函数是一个视图函数,它在查询时返回令牌的符号。

@看法

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

   让(符号)= ERC20.symbol();

   返回(符号,);

}

3.小数点

decimals 函数是一个视图函数,它在查询时返回令牌的小数位数。

@看法

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

   let (decimals) = ERC20.decimals();

   返回(小数,);

}

4.总供应量

totalSupply 函数是一个返回代币总供应量的视图函数。

@看法

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

   让 (totalSupply) = ERC20.total_supply();

   返回(总供应量,);

}

5.余额

BalanceOf 函数是一个视图函数,它在查询时返回特定帐户拥有的总额。与该合约中的所有其他函数一样,它也调用了 Openzeppelin 库中的内部balance_of函数,但这次传递了一个参数 [account],即要查询其余额的账户。

@看法

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

   让(余额)= ERC20.balance_of(账户);

   返回(余额,);

}

六、津贴

这是一个视图函数,用于查询并返回所有者分配给消费者的代币数量。 

它有两个参数 [owner, spender]。

@看法

func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt, spender: felt) -> (remaining: Uint256) {

   let (allowance) = ERC20.allowance(owner, spender);

   回报(津贴,);

}

7. 转移

转账函数是一个外部函数,它接受两个参数 [recipient, amount] 并启动从发件人到指定收件人的转账。

@外部的

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

   收件人:毛毡,数量:Uint256

) -> (成功: 感觉到) {

   ERC20.transfer(收件人,金额);

   返回(真,);

}

8.转自

transferFrom 函数是一个外部函数,它允许花费者将所有者/发送者允许花费的一定数量的代币转移给指定的接收者。 

它接受三个参数 [发件人、收件人、数量]。

@外部的

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

   发件人:毛毡,收件人:毛毡,金额:Uint256

) -> (成功: 感觉到) {

   ERC20.transfer_from(发件人、收件人、金额);

   返回(真,);

}

9. 批准

approve 函数也是一个外部函数,用于批准支出者从所有者的钱包中花费一定数量的代币。 

它有两个参数 [spender, amount]。

@外部的

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

   支出者:毛毡,金额:Uint256

) -> (成功: 感觉到) {

   ERC20.approve(spender, amount);

   返回(真,);

}

恭喜,您刚刚完成了您的第一个 ERC20 合约! 

您可以在此处找到完整的合约代码。

部署

最后,我们需要将我们的合约部署到 Starknet 以与之交互。 

按照通常的步骤,我们将首先构建/编译,然后声明,最后部署。

构建您的 ERC20 代币

在构建你的合约之前,确保在你的 protostar.toml 中指定你的合约的正确路径,并使 Protostar 能够找到你的 lib 文件夹,其中包含你的 Openzeppelin 合约,添加代码片段:

开罗路径= [“lib”]

您的 protostar.toml 文件应如下所示:

[项目]

原星版本=“0.9.1”

库路径=“库”

开罗路径= [“lib”]

[合同]

ERC20 = ["src/ERC20.cairo"]

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

原星建造

构建你的 Starknet 合约

声明您的 ERC20 代币

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

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

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

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

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

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

声明你的 Starknet 合约

部署您的 ERC20 代币

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

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

部署你的 Starknet 合约

您已经将您的第一个 ERC20 代币部署到 Starknet!

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

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

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

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

推特——  @argentHq

工程 Twitter —  @argentDeveloper

领英——  @argentHq

Youtube——  @argentHQ

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

所有文章项目介绍

设置Cairo开发环境

2023-1-25 9:25:00

所有文章项目介绍

Shardeum Betanet 发布

2023-2-1 11:40:00

搜索