diff --git a/docs/Solana-Co-Learn/module1/custom-instruction/build-a-movie-review-app/README.md b/docs/Solana-Co-Learn/module1/custom-instruction/build-a-movie-review-app/README.md index 8231d9d7c..3fe302802 100644 --- a/docs/Solana-Co-Learn/module1/custom-instruction/build-a-movie-review-app/README.md +++ b/docs/Solana-Co-Learn/module1/custom-instruction/build-a-movie-review-app/README.md @@ -23,7 +23,7 @@ npm i 这是一个普通的 Next.js 应用程序,安装了一些模板组件和一些 Solana 依赖项,以帮助您节省时间。那里有一些模拟评论,请查看各个组件以感受该应用程序。 -您会注意到我们已将钱包上下文提供程序从 `_app.tsx` 移至其自己的组件。它的工作原理是一样的,只是将其与更大的应用程序分开,性能更高。应用程序现在所做的就是将您的评论记录到控制台中,我们将在 `Form.tsx` 中设置 `handleTransactionSubmit` 函数。我们走吧呜呜呜呜 +您会注意到我们已将钱包上下文提供程序从 `_app.tsx` 移至其自己的组件。它的工作原理是一样的,只是将其与更大的应用程序分开,性能更高。应用程序现在所做的就是将您的评论记录到控制台中,我们将在 `Form.tsx` 中设置 `handleTransactionSubmit` 函数。我们走吧呜呜呜呜。 ## 🗺 定义架构 @@ -37,7 +37,7 @@ npm i npm install @project-serum/borsh --force ``` -接下来前往 `Movie.ts` 导入 `borsh` 并在 Movie 类中添加架构(不要复制粘贴此内容): +接下来前往 `Movie.ts` 导入 `borsh` 并在 `Movie` 类中添加架构(不要复制粘贴此内容): ```ts // We're importing borsh @@ -74,7 +74,7 @@ export class Movie { ## 🌭 创建serialize方法 -现在我们知道数据是什么样子,我们需要编写将其序列化的方法。将其添加到 Movie 类中架构的正下方: +现在我们知道数据是什么样子,我们需要编写将其序列化的方法。将其添加到 `Movie `类中架构的正下方: ```ts serialize(): Buffer { diff --git a/docs/Solana-Co-Learn/module1/local_program_development/anchor_program_hello.md b/docs/Solana-Co-Learn/module1/local_program_development/anchor_program_hello.md index 004746805..e0f86756b 100644 --- a/docs/Solana-Co-Learn/module1/local_program_development/anchor_program_hello.md +++ b/docs/Solana-Co-Learn/module1/local_program_development/anchor_program_hello.md @@ -1,10 +1,10 @@ --- sidebar_position: 9 -sidebar_label: Anchor 合约框架实现 +sidebar_label: Anchor 合约框架实现 - hello, World sidebar_class_name: green --- -# Anchor 合约框架实现 +# Anchor 合约框架实现 - hello, World 让我们通过构建和部署 `Hello World!` 程序来进行练习。 diff --git a/docs/Solana-Co-Learn/module1/local_program_development/local_program_development.md b/docs/Solana-Co-Learn/module1/local_program_development/local_program_development.md index db7ea8867..0e0498d4f 100644 --- a/docs/Solana-Co-Learn/module1/local_program_development/local_program_development.md +++ b/docs/Solana-Co-Learn/module1/local_program_development/local_program_development.md @@ -11,7 +11,7 @@ sidebar_class_name: green 本地开发的基本流程如下 1. 安装 [Rust](https://www.rust-lang.org/tools/install) 和 [Solana CLI](https://docs.solana.com/cli/install-solana-cli-tools) -2. 使用Solana CLI,您可以使用**solana-test-validator**命令运行本地测试验证器,初始化账户等基本操作 +2. 使用`Solana CLI`,您可以使用**solana-test-validator**命令运行本地测试验证器,初始化账户等基本操作 3. 使用 `cargo build-sbf` 和 `solana program deploy` 命令在本地构建和部署程序 4. 使用 `solana logs` 命令查看程序日志 @@ -80,28 +80,28 @@ sh -c "$(curl -sSfL https://release.solana.com/v1.16.6/install)" ## Solana CLI基础 -Solana CLI是一个命令行界面工具,提供了一系列命令,用于与Solana集群进行交互。 +`Solana CLI`是一个命令行界面工具,提供了一系列命令,用于与Solana集群进行交互。 -在本课程中,我们将介绍一些最常见的命令,但您始终可以通过运行`solana --help`来查看所有可能的Solana CLI命令列表。 +在本课程中,我们将介绍一些最常见的命令,但您始终可以通过运行`solana --help`来查看所有可能的`Solana CLI`命令列表。 ### Solana CLI 配置 -Solana CLI存储了一些配置设置,这些设置会影响某些命令的行为。您可以使用以下命令查看当前的配置: +`Solana CLI`存储了一些配置设置,这些设置会影响某些命令的行为。您可以使用以下命令查看当前的配置: ```bash solana config get ``` `solana config get`命令将返回以下内容: -- 配置文件 - Solana CLI所在的文件位于您的计算机上 -- RPC URL - 您正在使用的端点,将您连接到本地主机、开发网络或主网络 -- WebSocket URL - 监听来自目标集群的事件的WebSocket(在设置RPC URL时计算) -- 密钥对路径 - 在运行Solana CLI子命令时使用的密钥对路径 -- Commitment - 提供了网络确认的度量,并描述了一个区块在特定时间点上的最终性程度 +- 配置文件 - `Solana CLI`所在的文件位于您的计算机上 +- `RPC URL` - 您正在使用的端点,将您连接到本地主机、开发网络或主网络 +- `WebSocket URL` - 监听来自目标集群的事件的`WebSocket`(在设置`RPC URL`时计算) +- 密钥对路径 - 在运行`Solana CLI`子命令时使用的密钥对路径 +- `Commitment` - 提供了网络确认的度量,并描述了一个区块在特定时间点上的最终性程度 -您可以随时使用`solana config set`命令更改您的Solana CLI配置,然后跟上您想要更新的设置。 +您可以随时使用`solana config set`命令更改您的`Solana CLI`配置,然后跟上您想要更新的设置。 -最常见的更改将是您要定位的集群。使用`solana config set --url`命令更改RPC URL。 +最常见的更改将是您要定位的集群。使用`solana config set --url`命令更改`RPC URL`。 ```bash # localhost @@ -115,7 +115,7 @@ solana config set --url devnet solana config set --url mainnet-beta ``` -同样地,您可以使用`solana config set --keypair`命令来更改密钥对路径。当运行命令时,Solana CLI将使用指定路径下的密钥对。 +同样地,您可以使用`solana config set --keypair`命令来更改密钥对路径。当运行命令时,`Solana CLI`将使用指定路径下的密钥对。 ```bash solana config set --keypair ~/ @@ -131,7 +131,7 @@ solana config set --keypair ~/ 通常在打开一个新的控制台并在测试验证器旁边运行`solana logs`命令会很有帮助。这将创建另一个持续进行的进程,用于流式传输与您配置的集群相关的日志。 -如果您的CLI配置指向本地主机,则日志将始终与您创建的测试验证器相关联,但您也可以从其他集群(如Devnet和Mainnet Beta)流式传输日志。当从其他集群流式传输日志时,您需要在命令中包含一个程序ID,以限制您所看到的日志仅针对您的特定程序。 +如果您的CLI配置指向本地主机,则日志将始终与您创建的测试验证器相关联,但您也可以从其他集群(如`Devnet`和`Mainnet Beta`)流式传输日志。当从其他集群流式传输日志时,您需要在命令中包含一个程序`ID`,以限制您所看到的日志仅针对您的特定程序。 ### 密钥相关 @@ -154,7 +154,7 @@ solana address solana balance ``` -要在Devnet或本地主机上进行SOL的空投,请使用`solana airdrop`命令。请注意,在Devnet上,每次空投限制为2个SOL。 +要在`Devnet`或`localhost`上进行SOL的空投,请使用`solana airdrop`命令。请注意,在`Devnet`上,每次空投限制为2个SOL。 ```bash solana airdrop 2 @@ -168,69 +168,13 @@ solana airdrop 2 到目前为止,我们已经介绍了一些CLI命令,这些命令应该能帮助您快速解决那些问题。 -## 在您的本地环境中开发Solana程序 - -### 创建一个新项目 - -要创建一个新的Rust包来编写Solana程序,您可以使用`cargo new --lib`命令,并指定您想要创建的新目录的名称。 - -```bash -cargo new --lib -``` - -这个命令将在命令的末尾创建一个以您指定的名称命名的新目录。这个新目录将包含一个描述包的`Cargo.toml`清单文件。 - -清单文件包含元数据,如名称、版本和依赖项(包)。要编写Solana程序,您需要更新`Cargo.toml`文件,将`solana-program`作为依赖项包括进去。您可能还需要添加下面显示的`[lib]`和`crate-type`行。 - -```toml -[package] -name = "" -version = "0.1.0" -edition = "2021" - -[features] -no-entrypoint = [] - -[dependencies] -solana-program = "~1.8.14" - -[lib] -crate-type = ["cdylib", "lib"] -``` - -在那个时候,你可以开始在src文件夹中编写你的程序。 - - -### 构建和部署 - -当你准备构建你的Solana程序时,你可以使用`cargo build-sbf`命令。 - -```bash -cargo build-sbf -``` - -这个命令的输出将包含部署程序的指令,大致如下: - -```bash -To deploy this program: - $ solana program deploy /Users/James/Dev/Work/solana-hello-world-local/target/deploy/solana_hello_world_local.so -The program address will default to this keypair (override with --program-id): - /Users/James/Dev/Work/solana-hello-world-local/target/deploy/solana_hello_world_local-keypair.json -``` - -当您准备部署程序时,请使用从`cargo build-sbf`命令输出的`solana program deploy`命令。这将把您的程序部署到CLI配置中指定的集群。 - -```bash -solana program deploy -``` - ### 挑战 现在轮到你独立构建一些东西了。尝试创建一个新的程序,将你自己的消息打印到程序日志中。这次将你的程序部署到Devnet而不是本地主机。 -记得使用`solana config set --url`命令将你的RPC URL更新为Devnet。 +记得使用`solana config set --url`命令将你的`RPC URL`更新为`Devnet`。 -只要你将连接和Solana Explorer的URL更新为指向Devnet而不是localhost,你就可以使用与演示中相同的客户端脚本来调用该程序。 +只要你将连接和[Solana Explorer](https://explorer.solana.com)的`URL`更新为指向`Devnet`而不是`localhost`,你就可以使用与演示中相同的客户端脚本来调用该程序。 ```ts let connection = new web3.Connection(web3.clusterApiUrl("devnet")); @@ -242,7 +186,7 @@ console.log( ); ``` -您还可以打开一个单独的命令行窗口,并使用`solana logs | grep " invoke" -A` 。在Devnet上使用`solana logs`时,您必须指定程序ID。否则,`solana logs`命令将返回来自Devnet的持续日志流。例如,您可以按照以下步骤监视对Token程序的调用,并显示每个调用的前5行日志: +您还可以打开一个单独的命令行窗口,并使用`solana logs | grep " invoke" -A` 。在`Devnet`上使用`solana logs`时,您必须指定程序`ID`。否则,`solana logs`命令将返回来自`Devnet`的持续日志流。例如,您可以按照以下步骤监视对`Token`程序的调用,并显示每个调用的前5行日志: ```bash solana logs | grep "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke" -A 5 diff --git a/docs/Solana-Co-Learn/module1/local_program_development/native_program_hello.md b/docs/Solana-Co-Learn/module1/local_program_development/native_program_hello.md index fc6d53d04..39c960b6e 100644 --- a/docs/Solana-Co-Learn/module1/local_program_development/native_program_hello.md +++ b/docs/Solana-Co-Learn/module1/local_program_development/native_program_hello.md @@ -1,10 +1,10 @@ --- sidebar_position: 8 -sidebar_label: 原始Solana合约实现 +sidebar_label: Native Solana合约实现 - hello, World sidebar_class_name: green --- -# 原始Solana合约实现 +# Native Solana合约实现 - hello, World 让我们通过构建和部署 `Hello World!` 程序来进行练习。 diff --git a/docs/Solana-Co-Learn/module1/local_program_development/solang_program_hello.md b/docs/Solana-Co-Learn/module1/local_program_development/solang_program_hello.md index 3769c4821..83039e795 100644 --- a/docs/Solana-Co-Learn/module1/local_program_development/solang_program_hello.md +++ b/docs/Solana-Co-Learn/module1/local_program_development/solang_program_hello.md @@ -1,10 +1,10 @@ --- sidebar_position: 10 -sidebar_label: 使用Solang编译器编译solidity合约实现 +sidebar_label: Solang solidity合约实现 - hello, World sidebar_class_name: green --- -# 使用`Solang`编译器编译solidity合约实现 +# Solang solidity合约实现 - hello, World 欢迎来到Solana入门指南!`Solang`是一个Solidity编译器,它允许您使用Solidity编程语言编写Solana程序,其他区块链中称为“智能合约”。 diff --git a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/staking-with-anchor/README.md b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/staking-with-anchor/README.md index e0d795279..9425c72e4 100644 --- a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/staking-with-anchor/README.md +++ b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/staking-with-anchor/README.md @@ -6,15 +6,15 @@ sidebar_class_name: green # 🥩 使用Anchor进行质押 -是时候将NFT质押计划和用户界面转换为Anchor了!你一直在努力开发的buildoor项目已经很棒了,但是如果将其转移到Anchor上,以后的工作会更简单。继续运用你所学的知识,完成以下任务: +是时候将NFT质押计划和用户界面转换为`Anchor`了!你一直在努力开发的buildoor项目已经很棒了,但是如果将其转移到Anchor上,以后的工作会更简单。继续运用你所学的知识,完成以下任务: -- 使用Anchor从头开始重写程序。 +- 使用`Anchor`从头开始重写程序。 - 增加一些可靠的测试覆盖率,以确保您不会让安全风险从中溜走 -- 用Anchor方法构建器替换复杂的UI代码 +- 用`Anchor`方法构建器替换复杂的UI代码 你应该花一些时间独立尝试做这件事。这不是一项简单的任务,但你能行。如果几个小时后你感到困惑,可以随时观看我们解决方案的视频演示。 -让我们来完成这个任务并检查已发货的产品。我们将完善我们一直在努力开发的质押计划,但不是添加新功能,而是将其全部替换为Anchor。 +让我们来完成这个任务并检查已发货的产品。我们将完善我们一直在努力开发的质押计划,但不是添加新功能,而是将其全部替换为`Anchor`。 让我们通过运行 `anchor init anchor-nft-staking` 来创建一个新项目,或者选择一个你自己的名字。进入 `Anchor.toml` 文件,并将种子设置为 `true` ,集群设置为 `devnet` 。 diff --git a/docs/Solana-Co-Learn/module5/anchor-on-the-front-end/anchor-into-typescript/README.md b/docs/Solana-Co-Learn/module5/anchor-on-the-front-end/anchor-into-typescript/README.md index 83f09f12a..61e9a502d 100644 --- a/docs/Solana-Co-Learn/module5/anchor-on-the-front-end/anchor-into-typescript/README.md +++ b/docs/Solana-Co-Learn/module5/anchor-on-the-front-end/anchor-into-typescript/README.md @@ -6,9 +6,9 @@ sidebar_class_name: green # 🐹 Anchor到Typescript -要使用前端与程序进行交互,我们需要创建一个 Anchor `Program` 对象。 +要使用前端与程序进行交互,我们需要创建一个 `Anchor` `Program` 对象。 - `Program` 对象提供了一个自定义的API,通过结合程序 `IDL` 和 `Provider` 来与特定程序进行交互。 + `Program` 对象提供了一个自定义的`API`,通过结合程序 `IDL` 和 `Provider` 来与特定程序进行交互。 创建 `Program` 对象,我们需要以下内容: @@ -60,11 +60,11 @@ sidebar_class_name: green } ] } -``` + ``` ## Provider 供应商 -在使用 `IDL` 创建`Program`对象之前,我们首先需要创建一个Anchor `Provider` 对象。 +在使用 `IDL` 创建`Program`对象之前,我们首先需要创建一个`Anchor` `Provider` 对象。 `Provider` 对象代表了两个事物的组合: diff --git a/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-cpis/README.md b/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-cpis/README.md index b2b62ba94..abab08001 100644 --- a/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-cpis/README.md +++ b/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-cpis/README.md @@ -6,7 +6,7 @@ sidebar_class_name: green # 使用Anchor CPIs构建 -回到未来。我们将以CPIs结束我们的电影评论节目,来个圆满收官。 +回到未来。我们将以`CPIs`结束我们的电影评论节目,来个圆满收官。 这一次,让我们: @@ -18,7 +18,7 @@ sidebar_class_name: green **初始代码** - 起始代码:[https://beta.solpg.io/63184c17bb7e0b5f4ca6dfa5](https://beta.solpg.io/63184c17bb7e0b5f4ca6dfa5?utm_source=buildspace.so&utm_medium=buildspace_project) -- 我们将在之前的PDA演示基础上进行扩展 +- 我们将在之前的`PDA`演示基础上进行扩展 我们要做的第一件事是定义 `create_reward_mint` 指令: @@ -71,7 +71,7 @@ pub fn create_reward_mint( } ``` -这个很长但非常简单!我们正在为`Token`元数据程序创建一个CPI到 `create_metadata_account_v2` 指令。 +这个很长但非常简单!我们正在为`Token`元数据程序创建一个`CPI`到 `create_metadata_account_v2` 指令。 接下来,我们看到了 `CreateTokenReward` 上下文类型。 @@ -108,7 +108,7 @@ pub struct CreateTokenReward<'info> { ## 创建 ErrorCode - 检查评级的错误代码 -- (Anchor处理了我们在原生版本中的其他检查) +- (`Anchor`处理了我们在原生版本中的其他检查) ```rust #[error_code] diff --git a/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-pdas/README.md b/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-pdas/README.md index db7f4a92f..c679a3e10 100644 --- a/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-pdas/README.md +++ b/docs/Solana-Co-Learn/module5/program-in-anchor/build-with-anchor-pdas/README.md @@ -6,12 +6,12 @@ sidebar_class_name: green # 使用Anchor PDA构建 -在我们继续讨论CPI之前,让我们向世界展示一下这些PDA的功能。🎸 +在我们继续讨论`CPI`之前,让我们向世界展示一下这些`PDA`的功能。🎸 -我们将使用Anchor框架创建一个电影评论程序。 +我们将使用`Anchor`框架创建一个电影评论程序。 该程序将允许用户: -- 使用PDA初始化一个新的电影评论账户,以存储评论 +- 使用`PDA`初始化一个新的电影评论账户,以存储评论 - 更新现有的电影评论账户的内容 - 关闭现有的电影评论账户 @@ -33,7 +33,7 @@ pub mod movie_review { ## 🎥 MovieAccountState -我们首先要做的是定义State账户。 +我们首先要做的是定义`State`账户。 ```rust use anchor_lang::prelude::*; @@ -66,7 +66,7 @@ pub struct MovieAccountState { ## 🎬 添加电影评论 -感谢 Anchor,可以跳过所有验证和安全性,直接添加 `add_move_review` 功能: +感谢 `Anchor`,可以跳过所有验证和安全性,直接添加 `add_move_review` 功能: ```rust #[program] @@ -127,9 +127,9 @@ pub struct AddMovieReview<'info> { ... ``` -再次,我们正在以与本地相同的方式进行操作,但借助Anchor的魔力。 +再次,我们正在以与本地相同的方式进行操作,但借助`Anchor`的魔力。 -我们正在使用两个 seeds 初始化一个新的 `movie_review` 账户 +我们正在使用两个 `seeds` 初始化一个新的 `movie_review` 账户 - `title` - 指令数据中的电影标题 - `initializer.key()` - 创建电影评论的 `initializer` 的公钥 @@ -201,7 +201,7 @@ pub struct UpdateMovieReview<'info> { ... ``` -我们使用 `seeds` 和 `bump` 约束来验证 `movie_review` 账户。由于占用的空间可能会发生变化,我们使用 `realloc` 约束让Anchor根据更新的描述长度来处理账户空间和租金的重新分配。 +我们使用 `seeds` 和 `bump` 约束来验证 `movie_review` 账户。由于占用的空间可能会发生变化,我们使用 `realloc` 约束让`Anchor`根据更新的描述长度来处理账户空间和租金的重新分配。 `realloc::payer` 约束规定了所需的额外`lamports`将来自或发送到初始化账户。 @@ -253,7 +253,7 @@ pub struct Close<'info> { 我们都完成了!试一下,它会像旧的本地电影评论程序一样运行。如果出现问题,你可以与[这里](https://beta.solpg.io/631b39c677ea7f12846aee8c?utm_source=buildspace.so&utm_medium=buildspace_project)的解决方案代码进行比较 :) -## 🚢 船舶挑战 +## 🚢 Ship 挑战 (这个和build with solana Framework的内容重复了) 现在轮到你独立构建一些东西了。由于我们从非常简单的程序开始,你的程序将几乎与我们刚刚创建的程序完全相同。尽量达到能够独立编写代码而不参考之前的代码的程度,所以请尽量不要在这里复制粘贴。 diff --git a/docs/Solana-Co-Learn/module5/program-in-anchor/cpis-in-anchor/README.md b/docs/Solana-Co-Learn/module5/program-in-anchor/cpis-in-anchor/README.md index c6d82ae4f..3b31cce44 100644 --- a/docs/Solana-Co-Learn/module5/program-in-anchor/cpis-in-anchor/README.md +++ b/docs/Solana-Co-Learn/module5/program-in-anchor/cpis-in-anchor/README.md @@ -10,17 +10,17 @@ sidebar_class_name: green 回想一下,`CPI`是使用 `invoke` 和 `invoke_signed` 制作的。 -Anchor还提供了一种制作`CPI`的格式。使用这种格式需要访问所调用程序的`CPI`模块。常见的程序有一个你可以使用的包,例如 `anchor_spl` 用于令牌程序。否则,你将需要使用所调用程序的源代码或已发布的`IDL`来生成`CPI`模块。 +`Anchor`还提供了一种制作`CPI`的格式。使用这种格式需要访问所调用程序的`CPI`模块。常见的程序有一个你可以使用的包,例如 `anchor_spl` 用于令牌程序。否则,你将需要使用所调用程序的源代码或已发布的`IDL`来生成`CPI`模块。 -如果没有可用的CPI模块,您仍然可以直接在指令中使用 `invoke` 和 `invoke_signed` 。就像锚定指令需要 `Context` 类型一样,锚定CPI使用 `CpiContext` 。 +如果没有可用的`CPI`模块,您仍然可以直接在指令中使用 `invoke` 和 `invoke_signed` 。就像锚定指令需要 `Context` 类型一样,`Anchor` `CPI`使用 `CpiContext` 。 -`CpiContext`提供了指令所需的所有账户和种子。当没有PDA签名者时,使用`CpiContext::new`。 +`CpiContext`提供了指令所需的所有账户和种子。当没有`PDA`签名者时,使用`CpiContext::new`。 ```rust CpiContext::new(cpi_program, cpi_accounts) ``` -当需要一个PDA作为签名者时,使用 CpiContext::new_with_signer 。 +当需要一个`PDA`作为签名者时,使用 `CpiContext::new_with_signer` 。 ```rust CpiContext::new_with_signer(cpi_program, cpi_accounts, seeds) @@ -43,7 +43,7 @@ where } ``` -当不需要 `signer_seeds` 时使用 `CpiContext::new` (不使用PDA签名)。 +当不需要 `signer_seeds` 时使用 `CpiContext::new` (不使用`PDA`签名)。 ```rust pub fn new( @@ -78,7 +78,7 @@ pub fn new_with_signer( `anchor_spl` 包含一个 `token` 模块,用于简化创建`CPI`到令牌程序的过程。 -`Structs` 这是每个相应的令牌程序指令所需的账户列表。`Functions` 这是每个相应指令的CPI。 +`Structs` 这是每个相应的令牌程序指令所需的账户列表。`Functions` 这是每个相应指令的`CPI`。 例如,这里`MintTo`是所需的账户: @@ -93,7 +93,7 @@ pub struct MintTo<'info> { 让我们也来看看`mint_to`引擎的内部。 -它使用 `CpiContext` 来构建一个`CPI`到 `mint_to` 指令。它使用 `invoke_signed` 来制作CPI。 +它使用 `CpiContext` 来构建一个`CPI`到 `mint_to` 指令。它使用 `invoke_signed` 来制作`CPI`。 ```rust pub fn mint_to<'a, 'b, 'c, 'info>( @@ -170,7 +170,7 @@ token::mint_to( 错误可以分为以下几种类型: -- anchor框架从其自身代码内部返回的内部错误 +- `Anchor`框架从其自身代码内部返回的内部错误 - 用户(你!)可以返回的自定义错误 `AnchorErrors`提供了各种信息,例如: @@ -181,7 +181,7 @@ token::mint_to( 最终,所有的程序都会返回相同的错误:[ProgramError](https://docs.rs/solana-program/latest/solana_program/program_error/enum.ProgramError.html?utm_source=buildspace.so&utm_medium=buildspace_project)。 -Anchor有许多不同的内部错误代码。这些代码不是为用户使用的,但研究参考资料以了解代码和其原因之间的映射是很有用的。 +`Anchor`有许多不同的内部错误代码。这些代码不是为用户使用的,但研究参考资料以了解代码和其原因之间的映射是很有用的。 自定义错误代码编号从自定义错误偏移量开始。 diff --git a/docs/Solana-Co-Learn/module5/program-in-anchor/pdas-in-anchor/README.md b/docs/Solana-Co-Learn/module5/program-in-anchor/pdas-in-anchor/README.md index aac7a1f49..97470ca99 100644 --- a/docs/Solana-Co-Learn/module5/program-in-anchor/pdas-in-anchor/README.md +++ b/docs/Solana-Co-Learn/module5/program-in-anchor/pdas-in-anchor/README.md @@ -6,10 +6,9 @@ sidebar_class_name: green # 🛣 Anchor中的PDA -## 🛣 锚点中的PDA +## 🛣 PDAs in Anchor - -现在你很棒。让我们把它提升到11。 +现在你很棒。让我们继续。 在本课程中,我们将讨论如何使用 `#[account(...)]` 属性,并介绍以下限制条件: @@ -17,20 +16,20 @@ sidebar_class_name: green - `realloc` - 重新分配账户上的空间 - `close` - 关闭账户 -## 🛣 锚点中的PDA +## 🛣 PDAs in Anchor -回想一下,[PDA](https://github.com/Unboxed-Software/solana-course/blob/main/content/pda.md?utm_source=buildspace.so&utm_medium=buildspace_project)是使用一系列可选的种子、一个凸起的种子和一个 `programId` 来衍生的。锚点提供了一种方便的方法来验证带有 seeds 和 `bump` 约束的`PDA`。 +回想一下,[PDA](https://github.com/Unboxed-Software/solana-course/blob/main/content/pda.md?utm_source=buildspace.so&utm_medium=buildspace_project)是使用一系列可选的种子、一个`bump seed`和一个 `programId` 来衍生的。`Anchor`提供了一种方便的方法来验证带有 `seeds` 和 `bump` 约束的`PDA`。 ![](./img/pda.png) 在账户验证过程中,Anchor将使用 `seeds` 约束中指定的种子生成一个`PDA`,并验证传入指令的账户是否与使用指定 `seeds` 找到的`PDA`匹配。 -当包含碰撞约束但未指定具体碰撞时,Anchor将默认使用规范碰撞(即导致有效`PDA`的第一个碰撞)。 +当包含`bump`约束时,但未指定具体`bump`时,`Anchor`将默认使用规范`bump`(即查找有效`PDA`的第一个`bump`)。 ![](./img/example-pda.png) -在这个例子中,使用种子和碰撞约束来验证`pda_account`的地址是否是预期的`PDA`。 +在这个例子中,使用`seed`和`bump`约束来验证`pda_account`的地址是否是预期的`PDA`。 用于推导`PDA`的 `seeds` 包括: @@ -51,7 +50,7 @@ sidebar_class_name: green ![](./img/example-pda-2.png) -您可以将 `init` 约束与 `seeds` 和 `bump` 约束结合使用,使用PDA初始化账户。 +您可以将 `init` 约束与 `seeds` 和 `bump` 约束结合使用,使用`PDA`初始化账户。 `init` 约束必须与以下内容结合使用: @@ -59,25 +58,25 @@ sidebar_class_name: green - `space` - 为新账户分配的空间 - `system_program` - `init` 约束要求在账户验证结构中存在 `system_program` -默认情况下,init将创建的账户的所有者设置为当前正在执行的程序。 +默认情况下,`init`将创建的账户的所有者设置为当前正在执行的程序。 - 使用 `init` 与 `seeds` 和 `bump` 来初始化`PDA`账户时,所有者必须是执行程序。 - 这是因为创建一个账户需要一个签名,只有执行程序的`PDAs`才能提供 - (即,如果用于派生`PDA`的`programId`与执行程序的`programId`不匹配,则`PDA`帐户初始化的签名验证将失败)。 - 由于 `init` 使用 `find_program_address` 来推导`PDA`,因此无需指定 `bump` 的值。 -- 这意味着PDA将使用`canonical bump`起来推导。 -- 在为由执行的锚定程序初始化和拥有的账户分配 `space` 时,请记住前8个字节是保留给唯一账户辨别器的,锚定程序使用该辨别器来识别程序账户类型。 +- 这意味着`PDA`将使用规范的`bump`起来推导。 +- 在为由执行的`Anchor`程序初始化和拥有的账户分配 `space` 时,请记住前8个字节是保留给唯一账户`discriminator`的,`Anchor`程序使用该`discriminator`来识别程序账户类型。 ## 🧮 重新分配 -更多时候,你会更新现有的账户,而不是创建新的账户。Anchor拥有令人赞叹的`realloc`约束条件,为现有账户提供了一种简单的方式来重新分配空间。 +更多时候,你会更新现有的账户,而不是创建新的账户。`Anchor`拥有令人赞叹的`realloc`约束条件,为现有账户提供了一种简单的方式来重新分配空间。 ![](./img/realloc.png) `realloc` 约束必须与以下内容结合使用: - `mut` - 账户必须设置为可变的 -- `realloc::payer` - 根据重新分配的账户空间是减少还是增加,来减少或增加拉姆波特的账户 +- `realloc::payer` - 根据重新分配的账户空间是减少还是增加,来减少或增加账户的`lamports` - `realloc::zero` - 一个布尔值,用于指定是否应该将新内存初始化为零 - `system_program` - `realloc` 约束要求在账户验证结构中存在 `system_program` @@ -89,7 +88,7 @@ sidebar_class_name: green - 需要 `realloc::zero` 约束以确定在重新分配后是否应该对新内存进行零初始化。 - 在之前减少过的账户上扩展空间时,应将此约束设置为true。 -## ❌ 关闭 +## ❌ `close` 当你完成一个账户并且不想让它存在时会发生什么?你可以关闭它! @@ -99,8 +98,8 @@ sidebar_class_name: green ![](./img/close.png) -- `close` 约束在指令执行结束时将账户标记为已关闭,通过将其鉴别器设置为 `CLOSED_ACCOUNT_DISCRIMINATOR` 并将其 `lamports` 发送到指定的账户。 -- 将鉴别器设置为特殊变体可以防止账户复活攻击(即后续指令再次添加租金豁免的`lamports`)。 +- `close` 约束在指令执行结束时将账户标记为已关闭,通过将其`discriminator`设置为 `CLOSED_ACCOUNT_DISCRIMINATOR` 并将其 `lamports` 发送到指定的账户。 +- 将`discriminator`设置为特殊变体可以防止账户复活攻击(即后续指令再次添加租金豁免的`lamports`)。 - 我们将关闭 `data_account` 并将分配给租金的`lamports`发送到 `receiver` 账户。 - 然而,目前任何人都可以调用关闭指令并关闭 `data_account` diff --git a/docs/Solana-Co-Learn/module6/randomness/build-a-randomiser/README.md b/docs/Solana-Co-Learn/module6/randomness/build-a-randomiser/README.md index 492c8c188..b90cf115d 100644 --- a/docs/Solana-Co-Learn/module6/randomness/build-a-randomiser/README.md +++ b/docs/Solana-Co-Learn/module6/randomness/build-a-randomiser/README.md @@ -27,7 +27,7 @@ import * as sbv2 from "@switchboard-xyz/switchboard-v2" 对于实际功能,你会注意到我们传入的三个项目是提供者、战利品箱计划和付款人。 -我们要做的第一件事是加载devnet队列,这为我们提供了一个在devnet上进行测试的环境。ID是switchboard的程序ID,而100,000,000是switchboard代币,我们需要访问它们的内容。 +我们要做的第一件事是加载devnet队列,这为我们提供了一个在devnet上进行测试的环境。`ID`是switchboard的程序ID,而100,000,000是`switchboard`代币,我们需要访问它们的内容。 ```ts export const setupSwitchboard = async (provider, lootboxProgram, payer) => { @@ -58,9 +58,9 @@ console.log( ); ``` -上述的const状态是关键组件,它加载了我们需要的交换机队列数据,我们将在函数的其余部分中使用它。 +上述的`const`状态是关键组件,它加载了我们需要的交换机队列数据,我们将在函数的其余部分中使用它。 -然后我们创建我们的验证随机函数(VRF)账户。这对于我们使用的交换机板的部分非常特殊。正如您所看到的,它会生成一个新的密钥对。 +然后我们创建我们的验证随机函数(`VRF`)账户。这对于我们使用的交换机板的部分非常特殊。正如您所看到的,它会生成一个新的密钥对。 @@ -70,7 +70,7 @@ console.log( const vrfKeypair = anchor.web3.Keypair.generate() ``` -作为创建VRF账户的一部分,我们需要访问一些PDA设备。 +作为创建`VRF`账户的一部分,我们需要访问一些`PDA`设备。 @@ -88,11 +88,11 @@ lootboxProgram.programId ) ``` -你会看到我们正在使用vrf和payer的公钥作为种子。在生产环境中,这些将需要是静态的,只有payer的公钥。这段代码确保我们每次运行测试时都有不同的vrf密钥对和用户状态,这样我们在测试过程中不会遇到尝试重新创建已经创建过的账户的问题。 +你会看到我们正在使用`vrf`和`payer`的公钥作为种子。在生产环境中,这些将需要是静态的,只有`payer`的公钥。这段代码确保我们每次运行测试时都有不同的`vrf`密钥对和用户状态,这样我们在测试过程中不会遇到尝试重新创建已经创建过的账户的问题。 -现在我们可以使用sbv2库创建VRF账户,传入交换机程序、我们想要给VRF账户的密钥对、用户状态PDA作为授权、交换机队列和回调函数。 +现在我们可以使用`sbv2`库创建`VRF`账户,传入交换机程序、我们想要给`VRF`账户的密钥对、用户状态`PDA`作为授权、交换机队列和回调函数。 -所以,当我们想要一个新的随机数时,我们将通过与交换机程序进行CPI来获取一个随机数,并且它必须知道我们程序中的一条指令来进行CPI返回,以给我们随机数。与所有指令一样,它有一个程序ID,一个账户列表和指令数据。至于账户,第一个是用来为我们写入数据的地方,然后是vrf账户,我们将在其中写入已选择的mint的lootbox指针PDA,最后是付款人。 +所以,当我们想要一个新的随机数时,我们将通过与交换机程序进行`CPI`来获取一个随机数,并且它必须知道我们程序中的一条指令来进行`CPI`返回,以给我们随机数。与所有指令一样,它有一个程序ID,一个账户列表和指令数据。至于账户,第一个是用来为我们写入数据的地方,然后是vrf账户,我们将在其中写入已选择的`mint`的`lootbox`指针`PDA`,最后是付款人。 ```ts // create new vrf acount @@ -151,7 +151,7 @@ lootboxProgram.programId } ``` -由于我们稍后需要切换板账户的提升,我们将其提取出来,以及switchboardStateBump,这是切换板的程序账户。 +由于我们稍后需要切换板账户的提升,我们将其提取出来,以及`switchboardStateBump`,这是切换板的程序账户。 ```ts // GET PERMISSION BUMP AND SWITCHBOARD STATE BUMP @@ -180,7 +180,7 @@ return { } ``` -我们最终在我们的测试环境设置中调用整个函数,所以我们的before现在看起来是这样的。 +我们最终在我们的测试环境设置中调用整个函数,所以我们的`before`现在看起来是这样的。 ```ts before(async () => { @@ -202,25 +202,25 @@ before(async () => { 这是关于客户端交换机所需的基本知识。 -## init_user指令的详细步骤 👶 +## `init_user`指令的详细步骤 👶 -首先,对于我们的战利品箱计划,我们之前把所有东西都放在 lib.rs 里,但是它变得越来越庞大且难以控制,所以现在我们对其进行了拆分,请[查看](https://github.com/Unboxed-Software/anchor-nft-staking-program/tree/solution-randomize-loot/programs/lootbox-program?utm_source=buildspace.so&utm_medium=buildspace_project)文件结构。 +首先,对于我们的战利品箱计划,我们之前把所有东西都放在 `lib.rs` 里,但是它变得越来越庞大且难以控制,所以现在我们对其进行了拆分,请[查看](https://github.com/Unboxed-Software/anchor-nft-staking-program/tree/solution-randomize-loot/programs/lootbox-program?utm_source=buildspace.so&utm_medium=buildspace_project)文件结构。 -现在的lib文件主要只是一堆use语句、declare id宏和我们的四个指令,它们只是调用其他文件而已。 +现在的`lib`文件主要只是一堆`use`语句、`declare_id!`宏和我们的四个指令,它们只是调用其他文件而已。 -Init_user将创建用户状态账户,我们将在我们的程序和交换机之间共享该账户,它就像一个联络账户。 +`Init_user`将创建用户状态账户,我们将在我们的程序和交换机之间共享该账户,它就像一个联络账户。 -打开战利品箱与以前一样,它将启动生成随机货币的过程,但不会完成该过程,而是生成一个CPI来呼叫交换机以请求一个随机数。 +打开战利品箱与以前一样,它将启动生成随机货币的过程,但不会完成该过程,而是生成一个`CPI`来呼叫交换机以请求一个随机数。 消耗随机性是由交换机调用的,以返回指令中的号码,以便我们可以使用它,并在设置薄荷时完成该过程。 从战利品箱中获取物品基本上没有改变。 -让我们开始吧,首先是init_user。 +让我们开始吧,首先是`init_user`。 -在顶部,您会找到初始用户上下文,在底部是一个实现,其中有一个名为process instruction的函数,在该函数中执行了之前在lib文件中的逻辑。 +在顶部,您会找到初始用户上下文,在底部是一个实现,其中有一个名为`process instruction`的函数,在该函数中执行了之前在lib文件中的逻辑。 -在InitUser上下文中有四个账户。状态是我们的用户状态对象,其中包含vrf和payer密钥种子,这是用于测试的版本。对于生产代码,您只需要payer种子。我们这样做是为了节省时间,而不是使用环境变量。然后有vrf账户,switchboard不会自动加载它,因此需要使用.load()调用来加载。可能有其他使用switchboard的方法,但我们目前使用的是最简单/最快的路径来启动和运行,随时可以探索和改进它。最后,我们有payer和system程序来创建一个新账户。 +在InitUser上下文中有四个账户。状态是我们的用户状态对象,其中包含`vrf`和`payer`密钥种子,这是用于测试的版本。对于生产代码,您只需要payer种子。我们这样做是为了节省时间,而不是使用环境变量。然后有vrf账户,switchboard不会自动加载它,因此需要使用.load()调用来加载。可能有其他使用switchboard的方法,但我们目前使用的是最简单/最快的路径来启动和运行,随时可以探索和改进它。最后,我们有`payer`和`system`程序来创建一个新账户。 ```ts use crate::*; @@ -254,7 +254,7 @@ pub struct InitUser<'info> { } ``` -对于逻辑部分,我们正在获取一个名为state的账户,因为我们设置了bump、switchboard state bump、vrf permission bump、vrf账户以及与之关联的用户。你会注意到有一个结构体,它只包含我们之前提到的这两个bump。 +对于逻辑部分,我们正在获取一个名为`state`的账户,因为我们设置了`bump`、`switchboard state bump`、`vrf permission bump`、`vrf`账户以及与之关联的用户。你会注意到有一个结构体,它只包含我们之前提到的这两个`bump`。 ```rust #[derive(Clone, AnchorSerialize, AnchorDeserialize)] @@ -282,7 +282,7 @@ impl InitUser<'_> { 这里的新东西是结果缓冲区。这是我们提取随机性的地方,他们将其作为一个32字节的随机数据数组发送给我们,我们可以将其转化为我们需要的任何随机性。 -请注意,这里添加了两个属性, [account(zero_copy)] 是需要加载的部分,我只是按照交换机示例中的建议使用了它。 +请注意,这里添加了两个属性, `#[account(zero_copy)]` 是需要加载的部分,我只是按照交换机示例中的建议使用了它。 ```rust #[repr(packed)] diff --git a/docs/Solana-Co-Learn/module6/randomness/opening-loot-boxes/README.md b/docs/Solana-Co-Learn/module6/randomness/opening-loot-boxes/README.md index 2728dde03..f506fd442 100644 --- a/docs/Solana-Co-Learn/module6/randomness/opening-loot-boxes/README.md +++ b/docs/Solana-Co-Learn/module6/randomness/opening-loot-boxes/README.md @@ -8,18 +8,18 @@ sidebar_class_name: green 我们要进入开放的战利品箱指南,第一件你会注意到的事情是,它需要很多账号,总共19个! -直到stake_state,这些都是我们之前拥有的所有信息。 +直到`stake_state`,这些都是我们之前拥有的所有信息。 -与总机相关的内容我们正在添加的有:我们的用户状态,这是我们在初始化用户中刚刚初始化的。然后还有一堆总机账户,包括vrf账户、oracle队列账户、队列权限账户(这只是该权限的PDA)、数据缓冲区账户、权限账户、托管账户、程序状态账户和总机程序账户本身。 +与总机相关的内容我们正在添加的有:我们的用户状态,这是我们在初始化用户中刚刚初始化的。然后还有一堆总机账户,包括`vrf`账户、`oracle`队列账户、队列权限账户(这只是该权限的`PDA`)、数据缓冲区账户、权限账户、托管账户、程序状态账户和总机程序账户本身。 -你会注意到我们还没有讨论过一些类型,它们来自于 switchboard-v2 crate。以下是你需要添加到 Cargo.toml 中的两个依赖项,以使所有这些类型正常工作。 +你会注意到我们还没有讨论过一些类型,它们来自于 `switchboard-v2 crate`。以下是你需要添加到 `Cargo.toml` 中的两个依赖项,以使所有这些类型正常工作。 ```toml switchboard-v2 = { version = "^0.1.14", features = ["devnet"] } bytemuck = "1.7.2" ``` -最后两个账户是付款人钱包,它是与您的swithboard代币关联的代币账户,用于支付随机性和最近的区块哈希。 +最后两个账户是付款人钱包,它是与您的`swithboard`代币关联的代币账户,用于支付随机性和最近的区块哈希。 ```ts use crate::*; @@ -135,9 +135,9 @@ let vrf_permission_bump = state.vrf_permission_bump; drop(state); ``` -接下来,我们从账户列表中获取交换机程序本身。然后,我们构建VRF请求的随机性,这基本上是我们用于CPI的上下文,在我们几行后调用`vrf_request_randomness`时发生。 +接下来,我们从账户列表中获取交换机程序本身。然后,我们构建`VRF`请求的随机性,这基本上是我们用于`CPI`的上下文,在我们几行后调用`vrf_request_randomness`时发生。 -再次,你会注意到一些需要注释掉的代码,用于区分生产环境和测试环境。我们只在测试目的下使用vrf账户。 +再次,你会注意到一些需要注释掉的代码,用于区分生产环境和测试环境。我们只在测试目的下使用`vrf`账户。 ```rust let switchboard_program = ctx.accounts.switchboard_program.to_account_info(); @@ -189,7 +189,7 @@ ctx.accounts.lootbox_pointer.available_lootbox = box_number * 2; Ok(()) ``` -让我们回到战利品盒指针结构体,这里有一个 redeemable 属性。这个属性允许我们的客户端观察战利品盒指针账户,一旦它从false变为true,我们就知道随机性已经恢复,可以开始铸造。这个变化发生在消耗随机性函数中。 +让我们回到战利品盒指针结构体,这里有一个 `redeemable` 属性。这个属性允许我们的客户端观察战利品盒指针账户,一旦它从`false`变为`true`,我们就知道随机性已经恢复,可以开始铸造。这个变化发生在消耗随机性函数中。 ```rust #[account] @@ -202,7 +202,7 @@ pub struct LootboxPointer { } ``` -让我们跳转到那个函数并进行回顾。这是由交换机调用的函数,它是我们在 callback 文件中提供的内容。回调中的四个账户与ConsumeRandomness中的账户匹配,其中loobox指针和状态都是可变的。 +让我们跳转到那个函数并进行回顾。这是由交换机调用的函数,它是我们在 `callback` 文件中提供的内容。回调中的四个账户与`ConsumeRandomness`中的账户匹配,其中`loobox`指针和状态都是可变的。 ```rust use crate::state::*; @@ -237,7 +237,7 @@ pub struct ConsumeRandomness<'info> { } ``` -关于实际的实施,在过程指令功能中,我们首先加载vrf和状态账户。然后我们从vrf账户获取结果缓冲区,并检查确保其不为空。 +关于实际的实施,在过程指令功能中,我们首先加载vrf和状态账户。然后我们从`vrf`账户获取结果缓冲区,并检查确保其不为空。 @@ -382,7 +382,7 @@ const vrfState = await vrfAccount.loadData() recentBlockhashes: anchor.web3.SYSVAR_RECENT_BLOCKHASHES_PUBKEY, }) .rpc() - ``` +``` 然后我们有这个awaitCallback函数,在其中我们传入lootbox程序、指针PDA,并选择一个20秒的时间,在这段时间内,我们将等待看看lootbox指针是否更新为新的mint。