diff --git a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/build-the-front-end/README.md b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/build-the-front-end/README.md index deac136c1..8e626b0c5 100644 --- a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/build-the-front-end/README.md +++ b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/build-the-front-end/README.md @@ -8,9 +8,9 @@ sidebar_class_name: green 既然你已经让程序运行起来了,我们来进入前端代码,为Anchor进行调整。这个设置只需要一分钟,稍等一下,我们会修改一些东西。 -首先,让我们从我们的程序中引入我们的IDL。只需将整个文件复制并粘贴到 utils 文件夹中,包括JSON和TypeScript格式。 +首先,让我们从我们的程序中引入我们的`IDL`。只需将整个文件复制并粘贴到 `utils` 文件夹中,包括JSON和TypeScript格式。 -接下来,创建一个名为 WorkspaceProvider.ts 的新组件文件。为了节省一些时间,我们将从我们构建的电影评论前端中粘贴这段代码,然后将所有的"电影评论"实例更改为"锚定NFT质押"。你会注意到我们正在从常量文件夹中导入 PROGRAM_ID ,进入那里并确保程序ID是我们锚定NFT质押程序的新ID(而不是我们Solana原生程序的ID)。 +接下来,创建一个名为 `WorkspaceProvider.ts` 的新组件文件。为了节省一些时间,我们将从我们构建的电影评论前端中粘贴这段代码,然后将所有的"电影评论"实例更改为"Anchor NFT质押"。你会注意到我们正在从常量文件夹中导入 `PROGRAM_ID`s ,进入那里并确保程序`ID`是我们锚定NFT质押程序的新`ID`(而不是我们Solana原生程序的`ID`)。 ```typescript import { createContext, useContext } from "react" @@ -70,7 +70,7 @@ const MockWallet = { export { WorkspaceProvider, useWorkspace } ``` -还要从电影评论中复制模拟钱包文件,或者创建一个名为 MockWallet.ts 的新组件,并粘贴这段代码。 +还要从电影评论中复制模拟钱包文件,或者创建一个名为 `MockWallet.ts` 的新组件,并粘贴这段代码。 ```typescript import { Keypair } from "@solana/web3.js" @@ -84,13 +84,13 @@ const MockWallet = { export default MockWallet ``` -确保安装项目serum, npm install @project-serum/anchor 。 +确保安装项目`serum`, `npm install @project-serum/anchor` 。 -现在打开 npm run dev ,看看本地主机上是否一切正常...如果是的话,我们继续。 +现在打开 `npm run dev` ,看看本地主机上是否一切正常...如果是的话,我们继续。 既然我们已经准备好了进口和额外的组件,让我们仔细检查文件,看看我们可以在使用Anchor时简化事情的地方。 -跳转到(/pages/_app.tsx)并添加我们的新WorkspaceProvider,确保它被导入。 +跳转到(`/pages/_app.tsx`)并添加我们的新`WorkspaceProvider`,确保它被导入。 ```typescript function MyApp({ Component, pageProps }: AppProps) { @@ -120,7 +120,7 @@ import * as anchor from @project-serum/anchor let workspace = useWorkspace() ``` -然后在 checkStakingStatus 里面添加这个额外的检查,连同我们的其他检查一起,确保我们有 !workspace.program 。 +然后在 `checkStakingStatus` 里面添加这个额外的检查,连同我们的其他检查一起,确保我们有 `!workspace.program` 。 ```typescript if ( @@ -131,7 +131,7 @@ if ( ) ``` -现在跳转到 /utils/accounts.ts 。您可以删除所有的borsh代码,并将 getStakeAccount 代码替换为此代码。这是使用Anchor工作的美妙之处之一,我们不需要担心序列化和反序列化。 +现在跳转到 `/utils/accounts.ts` 。您可以删除所有的`borsh`代码,并将 `getStakeAccount` 代码替换为此代码。这是使用Anchor工作的美妙之处之一,我们不需要担心序列化和反序列化。 ```typescript export async function getStakeAccount( @@ -151,18 +151,16 @@ export async function getStakeAccount( 现在已经比以前简单多了,对吧?!? -回到 checkStakingStatus 在 StakeOptionsDisplay ,这里被称为 getStakeAccount ,将第一个参数从 connection 更改为 workspace.program 。 +回到 `checkStakingStatus` 在 `StakeOptionsDisplay` ,这里被称为 `getStakeAccount` ,将第一个参数从 `connection` 更改为 `workspace.program` 。 打开你的浏览器,确保本地主机上的一切功能正常。 -回到StakeOptionsDisplay,向下滚动到 handleStake 函数。 +回到`StakeOptionsDisplay`,向下滚动到 `handleStake` 函数。 -再次,首先添加一个检查 !workspace.program 的步骤。我们很快就会想要将其添加到我们的 handleUnstake 和 handleClaim 函数中。 +再次,首先添加一个检查 `!workspace.program` 的步骤。我们很快就会想要将其添加到我们的 `handleUnstake` 和 `handleClaim` 函数中。 你可以立即从我们之前的工作中删除所有这些代码。 - - ```typescript const account = await connection.getAccountInfo(stakeAccount) if (!account) { @@ -202,9 +200,9 @@ transaction.add( ) ``` -这也意味着我们在instructions.ts文件中创建的一堆代码不再需要了。再次跳转到浏览器上测试一下。 +这也意味着我们在`instructions.ts`文件中创建的一堆代码不再需要了。再次跳转到浏览器上测试一下。 -假设一切正常运作,让我们来解决 handleUnstake 代码。 +假设一切正常运作,让我们来解决 `handleUnstake` 代码。 我们抛弃这段代码,因为现在程序已经处理了这一切。 @@ -225,7 +223,7 @@ if (!account) { } ``` -然后在 transaction.add 里面去掉 createUnstakeInstruction 并用这个替换: +然后在 `transaction.add` 里面去掉 `createUnstakeInstruction` 并用这个替换: ```typescript transaction.add( @@ -243,9 +241,9 @@ transaction.add( ) ``` -你会注意到这些账户与 handleStake 相同,再加上一些用于股份铸币和用户ATA的账户。 +你会注意到这些账户与 `handleStake` 相同,再加上一些用于股份铸币和用户`ATA`的账户。 -最后,到 handleClaim ,按照相同的模式进行删除,新的transaction.add应该是这样的: +最后,到 `handleClaim` ,按照相同的模式进行删除,新的`transaction.add`应该是这样的: ```typescript transaction.add( @@ -260,12 +258,12 @@ transaction.add( ) ``` -现在你可以直接删除所有的 instructions.ts 文件。快点!!! :) +现在你可以直接删除所有的 `instructions.ts` 文件。快点!!! :) 随意清理掉未使用的导入以整理你的文件。 -还有一件事情我们需要做,在令牌目录中,我们已经创建了奖励令牌,现在需要用新的程序ID重新初始化它。在 bld/index.ts 文件中,当调用 await createBldToken 时,需要替换为新的程序ID。然后重新运行 npm run create-bld-token 脚本。如果我们不这样做,我们的兑换将无法正常工作。 +还有一件事情我们需要做,在令牌目录中,我们已经创建了奖励令牌,现在需要用新的程序`ID`重新初始化它。在 `bld/index.ts` 文件中,当调用 `await createBldToken` 时,需要替换为新的程序`ID`。然后重新运行 `npm run create-bld-token` 脚本。如果我们不这样做,我们的兑换将无法正常工作。 -这将创建一个新的Mint程序ID,您需要将其添加到您的环境变量中。 +这将创建一个新的`Mint`程序`ID`,您需要将其添加到您的环境变量中。 就是这样,我们在前端有一些功能正在运作。下周,我们将使用Anchor进行更多的发货,目前我们只是想展示它有多么容易,并让基本功能开始运行。 diff --git a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/redeeming-with-anchor/README.md b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/redeeming-with-anchor/README.md index 60c584b3e..b59818f6f 100644 --- a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/redeeming-with-anchor/README.md +++ b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/redeeming-with-anchor/README.md @@ -6,31 +6,31 @@ sidebar_class_name: green # 💸 Redeeming with Anchor -回到 lib.rs 文件,找到Redeem结构体。它与Stake非常相似,所以我们将粘贴该代码并根据需要进行编辑。 +回到 `lib.rs` 文件,找到`Redeem`结构体。它与`Stake`非常相似,所以我们将粘贴该代码并根据需要进行编辑。 -我们不需要的是nft_mint、nft_edition和program_authority。我们需要更改nft_token_account上的约束条件,使令牌授权变为'user',因为我们没有传入mint。 +我们不需要的是`nft_mint`、`nft_edition`和`program_authority`。我们需要更改`nft_token_account`上的约束条件,使令牌授权变为'`user`',因为我们没有传入`mint`。 -对于stake_state账户,它不再需要初始化,所以我们只需要种子和bump,并使其可变。我们还可以为其添加一些手动约束。 +对于`stake_state`账户,它不再需要初始化,所以我们只需要种子和`bump`,并使其可变。我们还可以为其添加一些手动约束。 ```rust constraint = *user.key == stake_state.user_pubkey, constraint = nft_token_account.key() == stake_state.token_account ``` -让我们再添加几个账户,其中一个是 stake_mint,需要是可变的。这是奖励铸币账户。 +让我们再添加几个账户,其中一个是 `stake_mint`,需要是可变的。这是奖励铸币账户。 ```rust #[account(mut)] pub stake_mint: Account<'info, Mint>, ``` -另一个是stake_authority,它将是另一个未经检查的账户,所以让我们添加这个检查。 +另一个是`stake_authority`,它将是另一个未经检查的账户,所以让我们添加这个检查。 ```rust #[account(seeds = ["mint".as_bytes().as_ref()], bump)] ``` -用户的 user_stake_ata 是一个 TokenAccount,具有以下限制条件。 +用户的 `user_stake_ata` 是一个 `TokenAccount`,具有以下限制条件。 ```rust #[account( @@ -42,13 +42,13 @@ pub stake_mint: Account<'info, Mint>, pub user_stake_ata: Account<'info, TokenAccount>, ``` -关联的 associated_token_program 是一个 AssociatedToken。 +关联的 `associated_token_program` 是一个 `AssociatedToken`。 ```rust pub associated_token_program: Program<'info, AssociatedToken>, ``` -最后,将metadata_program替换为rent。 +最后,将`metadata_program`替换为`rent`。 ```rust pub rent: Sysvar<'info, Rent>, @@ -109,7 +109,7 @@ it("Redeems", async () => { .rpc() ``` -...然后运行 anchor test ,如果一切正常并且两个测试通过,我们就进入函数并编写赎回逻辑。 +...然后运行 `anchor test` ,如果一切正常并且两个测试通过,我们就进入函数并编写赎回逻辑。 首先,让我们进行一些检查,一个是看它是否已初始化,另一个是确保它已经抵押。我们需要在文件底部为这两个情况添加自定义错误。 @@ -156,7 +156,7 @@ let redeem_amount = (10 * i64::pow(10, 2) * unix_time) / (24 * 60 * 60); msg!("Elligible redeem amount: {}", redeem_amount); ``` -好的,现在我们将实际铸造奖励。首先,我们需要使用我们的程序创建CpiContext。然后,我们在MintTo对象中传递账户信息,包括铸币对象、接收者和授权机构。最后,我们添加种子和金额。 +好的,现在我们将实际铸造奖励。首先,我们需要使用我们的程序创建`CpiContext`。然后,我们在`MintTo`对象中传递账户信息,包括铸币对象、接收者和授权机构。最后,我们添加种子和金额。 ```rust 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 7e249d048..e0d795279 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 @@ -16,9 +16,9 @@ sidebar_class_name: green 让我们来完成这个任务并检查已发货的产品。我们将完善我们一直在努力开发的质押计划,但不是添加新功能,而是将其全部替换为Anchor。 -让我们通过运行 anchor init anchor-nft-staking 来创建一个新项目,或者选择一个你自己的名字。进入 Anchor.toml 文件,并将种子设置为 true ,集群设置为 devnet 。 +让我们通过运行 `anchor init anchor-nft-staking` 来创建一个新项目,或者选择一个你自己的名字。进入 `Anchor.toml` 文件,并将种子设置为 `true` ,集群设置为 `devnet` 。 -然后跳转到 /programs/anchor-nft-staking/Cargo.toml ,添加以下依赖项。 +然后跳转到 `/programs/anchor-nft-staking/Cargo.toml` ,添加以下依赖项。 ```toml anchor-lang = { version="0.25.0", features = ["init-if-needed"] } @@ -26,7 +26,7 @@ anchor-spl = "0.25.0" mpl-token-metadata = { version="1.4.1", features=["no-entrypoint"] } ``` -好的,打开 lib.rs 文件,让我们构建基本的脚手架。 +好的,打开 `lib.rs` 文件,让我们构建基本的脚手架。 让我们添加以下导入,随着我们的进行,每个导入的必要性将变得清晰明了。 @@ -43,15 +43,15 @@ use mpl_token_metadata::{ }; ``` -让我们将默认函数的名称更改为 stake ,并将其相关上下文更改为类型 Stake 。 +让我们将默认函数的名称更改为 `stake` ,并将其相关上下文更改为类型 `Stake` 。 -然后添加一个名为 redeem 的函数,其上下文类型为 Redeem 。 +然后添加一个名为 `redeem` 的函数,其上下文类型为 `Redeem` 。 -最后,对于 unstake ,使用 Unstake 的上下文类型进行相同操作。 +最后,对于 `unstake` ,使用 `Unstake` 的上下文类型进行相同操作。 -这些是我们要构建的项目,我们首先要处理的是Stake的结构。 +这些是我们要构建的项目,我们首先要处理的是`Stake`的结构。 -我们需要一个PDA来存储UserStakeInfo,并且需要一个StakeState枚举来表示PDA的其中一个字段。 +我们需要一个`PDA`来存储`UserStakeInfo`,并且需要一个`StakeState`枚举来表示`PDA`的其中一个字段。 ```rust #[account] @@ -71,9 +71,9 @@ pub enum StakeState { } ``` -我们还可以为StakeState添加一个默认值,将其设置为未抵押。 +我们还可以为`StakeState`添加一个默认值,将其设置为未抵押。 -我们将使用元数据程序。由于这是相对较新的,锚定程序中没有相应的类型。为了像我们的其他程序(例如系统程序、令牌程序等)一样使用它,我们将为其创建一个结构体,并添加一个名为 id 的实现,返回一个 Pubkey ,它是 MetadataTokenId 。 +我们将使用元数据程序。由于这是相对较新的,锚定程序中没有相应的类型。为了像我们的其他程序(例如系统程序、令牌程序等)一样使用它,我们将为其创建一个结构体,并添加一个名为 `id` 的实现,返回一个 `Pubkey` ,它是 `MetadataTokenId` 。 ```rust @@ -89,9 +89,9 @@ impl anchor_lang::Id for Metadata { 好的,我们现在可以开始处理质押部分了。下面是结构体需要的总共九个账户。需要注意的几个事项。 -你会注意到 nft_edition 是一个 Unchecked 账户,这是因为系统中还没有为这种类型的账户创建。所有未核对的账户都需要有一个备注,以便系统知道你将添加手动安全检查,你会在下面看到 CHECK: Manual validation 。 +你会注意到 `nft_edition` 是一个 `Unchecked` 账户,这是因为系统中还没有为这种类型的账户创建。所有未核对的账户都需要有一个备注,以便系统知道你将添加手动安全检查,你会在下面看到 `CHECK: Manual validation` 。 -作为提醒,每个账户上的属性是安全检查,以确保账户是正确类型并能执行特定功能。由于用户需要支付,并且 NFT 代币账户将进行更改,两者都具有 mut 属性。一些账户还需要种子,如下所示。 +作为提醒,每个账户上的属性是安全检查,以确保账户是正确类型并能执行特定功能。由于用户需要支付,并且 NFT 代币账户将进行更改,两者都具有 `mut` 属性。一些账户还需要种子,如下所示。 所有其他没有任何属性的账户在Anchor中都有自己必需的安全检查,所以我们不需要添加任何属性。 @@ -127,9 +127,9 @@ pub struct Stake<'info> { } ``` -在我们继续之前,让我们运行 anchor build,这样我们的第一个构建就可以开始了。记住,这是我们的第一个构建,它将生成我们的程序ID。 +在我们继续之前,让我们运行 `anchor build`,这样我们的第一个构建就可以开始了。记住,这是我们的第一个构建,它将生成我们的程序ID。 -在运行的同时,在 tests 目录中创建一个名为 utils 的新文件夹。在其中创建一个名为 setupNft.ts 的文件。将下面的代码粘贴进去。 +在运行的同时,在 `tests` 目录中创建一个名为 `utils` 的新文件夹。在其中创建一个名为 `setupNft.ts` 的文件。将下面的代码粘贴进去。 ```ts import { @@ -194,9 +194,9 @@ export const setupNft = async (program, payer) => { ``` -下一次运行 npm install @metaplex-foundation/js 。 +下一次运行 `npm install @metaplex-foundation/js` 。 -然后跳转到 anchor-nft-staking.ts 目录中。这是Anchor创建的默认文件。 +然后跳转到 `anchor-nft-staking.ts` 目录中。这是Anchor创建的默认文件。 将提供者的默认行更改为两部分,这样我们以后需要时就可以访问提供者。 @@ -211,9 +211,9 @@ anchor.setProvider(provider) const wallet = anchor.workspace.AnchorNftStaking.provider.wallet ``` -检查您的构建情况,如果已完成,请运行 anchor deploy ,如果失败,您可能需要向自己空投一些SOL。 +检查您的构建情况,如果已完成,请运行 `anchor deploy` ,如果失败,您可能需要向自己空投一些SOL。 -构建完成后,运行 anchor keys list 并获取程序ID,然后放入 lib.rs 和 Anchor.toml 文件中。如果构建需要一段时间,您可能需要回到这一步。 +构建完成后,运行 `anchor keys list` 并获取程序`ID`,然后放入 `lib.rs` 和 `Anchor.toml` 文件中。如果构建需要一段时间,您可能需要回到这一步。 回到测试文件。 @@ -228,7 +228,7 @@ let mint: anchor.web3.PublicKey let tokenAddress: anchor.web3.PublicKey ``` -现在让我们添加一个 before 函数,在测试运行之前调用。你会注意到";"语法,它将解构返回值并设置所有这些值。 +现在让我们添加一个 `before` 函数,在测试运行之前调用。你会注意到"`;`"语法,它将解构返回值并设置所有这些值。 ```ts before(async () => { @@ -237,7 +237,7 @@ before(async () => { }) ``` -跳转到默认测试,将其更改为 it("Stakes", 。首先,我们只是确保函数被调用。我们还没有构建出实际的股权函数,所以这里没有进行任何逻辑测试。 +跳转到默认测试,将其更改为 `it("Stakes"`, 。首先,我们只是确保函数被调用。我们还没有构建出实际的股权函数,所以这里没有进行任何逻辑测试。 ```ts it("Stakes", async () => { @@ -255,17 +255,17 @@ it("Stakes", async () => { }) ``` -现在,运行 anchor test 。假设它通过了,这意味着我们通过了在Stake结构中创建的账户的验证。 +现在,运行 `anchor test` 。假设它通过了,这意味着我们通过了在`Stake`结构中创建的账户的验证。 回到我们的逻辑,以下是抵押工作所需的逐步操作。我们需要获取时钟的访问权限,确保抵押状态已经初始化,并确保它尚未被抵押。 -在stake函数中,让我们首先获取时钟。 +在`stake`函数中,让我们首先获取时钟。 ```rust let clock = Clock::get().unwrap(); ``` -接下来,我们创建一个CPI来委托该程序作为冻结或解冻我们的NFT的权限。首先,我们设置CPI,然后确定我们要使用的账户,最后设置权限。 +接下来,我们创建一个`CPI`来委托该程序作为冻结或解冻我们的NFT的权限。首先,我们设置`CPI`,然后确定我们要使用的账户,最后设置权限。 ```rust msg!("Approving delegate"); @@ -281,7 +281,7 @@ let cpi_approve_ctx = CpiContext::new(cpi_approve_program,cpi_approve_accounts); token::approve(cpi_approve_ctx, 1)?; ``` -接下来我们开始冻结代币。首先我们设置权限提升,然后调用invoke_signed函数,并传入所有必要的账户和账户信息数组,最后是种子和提升值。 +接下来我们开始冻结代币。首先我们设置权限提升,然后调用`invoke_signed`函数,并传入所有必要的账户和账户信息数组,最后是种子和提升值。 ```rust msg!("Freezing token account"); diff --git a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/unstaking-with-anchor/README.md b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/unstaking-with-anchor/README.md index 93a59902a..c26b6ecc1 100644 --- a/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/unstaking-with-anchor/README.md +++ b/docs/Solana-Co-Learn/module5/a-full-stack-anchor-app/unstaking-with-anchor/README.md @@ -72,11 +72,11 @@ it("Unstakes", async () => { ``` ``` -运行 anchor test 以确保我们的账户验证设置正确。 +运行 `anchor test` 以确保我们的账户验证设置正确。 回到实际的功能本身,这个功能比前两个要大一些。它与兑换非常相似,首先你可以粘贴那个代码,以节省一些打字。 -我们从相同的两个require语句开始。在这两个语句之后,我们需要“解冻”我们的账户。这段代码与冻结账户的invoke_signed非常相似,我们只需要反转几个步骤。 +我们从相同的两个`require`语句开始。在这两个语句之后,我们需要“解冻”我们的账户。这段代码与冻结账户的`invoke_signed`非常相似,我们只需要反转几个步骤。 假设你已经粘贴了兑换码,在声明时钟之前,添加这个。你会注意到它几乎完全相同,但我们显然是在调用解冻函数。 @@ -102,7 +102,7 @@ invoke_signed( )?; ``` -接下来我们需要撤销委托,同样,我们可以复制之前批准委托时的代码。将方法从approve改为revoke,并更改对象。只需要源代码和权限。确保还要更改变量名。最好在下面看一下,基本上我们只是将approve改为revoke。 +接下来我们需要撤销委托,同样,我们可以复制之前批准委托时的代码。将方法从`approve`改为`revoke`,并更改对象。只需要源代码和权限。确保还要更改变量名。最好在下面看一下,基本上我们只是将`approve`改为`revoke`。 ```rust msg!("Revoking delegate"); 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 8c996b297..b8286ea31 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 @@ -108,7 +108,7 @@ export class AnchorProvider implements Provider { > Note that the `Wallet` object provided by the `useWallet` hook from `@solana/wallet-adapter-react` is not compatible with the `Wallet` object that the Anchor `Provider` expects. -请注意,由 Wallet 钩子提供的对象与Anchor Provider 期望的 Wallet 对象不兼容。 +请注意,由 Wallet 钩子提供的对象与`Anchor Provider` 期望的 Wallet 对象不兼容。 那么,让我们来比较一下来自`useAnchorWallet`的`AnchorWallet`和来自`useWallet`的`WalletContextState`。 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 2200008dc..0464ad806 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 @@ -247,13 +247,13 @@ pub fn update_movie_review( Ok(()) } - ``` +``` ### 添加 `add_comment` -- Create `add_comment instruction` +- `Create add_comment instruction` - 设置 `movie_comment` 数据 -- CPI给 `mintTo` 指令,将代币铸造给审核者 +- `CPI`给 `mintTo` 指令,将代币铸造给审核者 ```rust pub fn add_comment(ctx: Context, comment: String) -> Result<()> { 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 ea4db045d..369f23b75 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 @@ -130,10 +130,10 @@ pub struct AddMovieReview<'info> { 再次,我们正在以与本地相同的方式进行操作,但借助Anchor的魔力。 -我们正在使用两个 seeds 初始化一个新的 movie_review 账户 +我们正在使用两个 seeds 初始化一个新的 `movie_review` 账户 -- title - 指令数据中的电影标题 -- initializer.key() - 创建电影评论的 initializer 的公钥 +- `title` - 指令数据中的电影标题 +- `initializer.key()` - 创建电影评论的 `initializer` 的公钥 我们也正在根据 `space` 账户类型的结构,将资金分配到新账户中。 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 b406b58b8..eb77b6378 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 @@ -188,7 +188,7 @@ Anchor有许多不同的内部错误代码。这些代码不是为用户使用 您可以使用 `error_code` 属性为您的程序添加独特的错误。只需将其添加到一个您选择的枚举中即可。然后,您可以将枚举的变体用作程序中的错误。 -此外,您可以使用 msg 为各个变体添加消息。如果发生错误,客户端将显示此错误消息。要实际抛出错误,请使用 `err!` 或 `error!` 宏。这些宏会将文件和行信息添加到错误中,然后由`anchor`记录。 +此外,您可以使用 `msg` 为各个变体添加消息。如果发生错误,客户端将显示此错误消息。要实际抛出错误,请使用 `err!` 或 `error!` 宏。这些宏会将文件和行信息添加到错误中,然后由`anchor`记录。 ```rust #[program] diff --git a/docs/Solana-Co-Learn/module6/finishing-touches/onwards/README.md b/docs/Solana-Co-Learn/module6/finishing-touches/onwards/README.md index 58b74ac04..acf9dfae0 100644 --- a/docs/Solana-Co-Learn/module6/finishing-touches/onwards/README.md +++ b/docs/Solana-Co-Learn/module6/finishing-touches/onwards/README.md @@ -12,6 +12,6 @@ sidebar_class_name: green 自己动手建造一些东西,参加黑客马拉松,抓住机会。你可以做任何事情。 -- [superteam](https://earn.superteam.fun/) +- [Superteam](https://earn.superteam.fun/) - [Solana Grant](https://solana.org/) - [Lamport Dao](https://twitter.com/lamportDAO) diff --git a/docs/Solana-Co-Learn/module6/finishing-touches/preparing-for-takeoff/README.md b/docs/Solana-Co-Learn/module6/finishing-touches/preparing-for-takeoff/README.md index 194e21743..24f52d007 100644 --- a/docs/Solana-Co-Learn/module6/finishing-touches/preparing-for-takeoff/README.md +++ b/docs/Solana-Co-Learn/module6/finishing-touches/preparing-for-takeoff/README.md @@ -1,5 +1,5 @@ --- -sidebar_position: 106 +sidebar_position: 107 sidebar_label: 🚀 准备起飞 sidebar_class_name: green --- @@ -8,7 +8,7 @@ sidebar_class_name: green 好的,让我们开始吧。在深入逻辑`/components/Lootbox.tsx`之前,让我们先快速浏览一下布局。 -我们将一切都集中在一起,只需进行三个检查:是否有可用的战利品箱、是否有押注账户,以及总收益是否大于战利品箱。如果是,它会呈现一个带有各种选项的盒子;否则,它会提示继续押注。我们很快会看一下 handleRedeemLoot 或 handleOpenLootbox 。 +我们将一切都集中在一起,只需进行三个检查:是否有可用的战利品箱、是否有押注账户,以及总收益是否大于战利品箱。如果是,它会呈现一个带有各种选项的盒子;否则,它会提示继续押注。我们很快会看一下 `handleRedeemLoot` 或 `handleOpenLootbox` 。 ```tsx return ( @@ -39,7 +39,7 @@ return ( ) ``` -在这个函数中,首先我们有大量的设置和状态。有一个useEffect来确保我们有一个公钥、一个战利品箱程序和一个质押程序,如果这些都存在,它调用 handleStateRefresh 。 +在这个函数中,首先我们有大量的设置和状态。有一个`useEffect`来确保我们有一个公钥、一个战利品箱程序和一个质押程序,如果这些都存在,它调用 `handleStateRefresh` 。 ```tsx export const Lootbox = ({ @@ -79,7 +79,7 @@ const handleStateRefresh = async ( } ``` - checkUserAccount 将获取用户状态PDA,如果存在,则调用 setUserAccountExist 并将其设置为true。 + `checkUserAccount` 将获取用户状态`PDA`,如果存在,则调用 `setUserAccountExist` 并将其设置为`true`。 ```tsx // check if UserState account exists @@ -105,7 +105,7 @@ const handleStateRefresh = async ( ``` -fetchLootboxPointer 基本上是获取战利品盒指针,设置可用的战利品盒和可兑换的货币。 +`fetchLootboxPointer` 基本上是获取战利品盒指针,设置可用的战利品盒和可兑换的货币。 ```tsx const fetchLootboxPointer = async ( @@ -132,9 +132,7 @@ const fetchLootboxPointer = async ( } ``` -回到两个主要的逻辑部分,一个是 handleOpenLootbox 。它首先检查我们是否拥有传递给函数所需的所有必要项目,然后调用 openLootbox 。 - - +回到两个主要的逻辑部分,一个是 `handleOpenLootbox` 。它首先检查我们是否拥有传递给函数所需的所有必要项目,然后调用 `openLootbox`。 ```tsx const handleOpenLootbox: MouseEventHandler = useCallback( @@ -169,7 +167,7 @@ const handleOpenLootbox: MouseEventHandler = useCallback( ) ``` -openLootbox 从检查用户账户是否存在开始,如果不存在,则调用指令文件中的 createInitSwitchboardInstructions ,该文件会返回给我们指令和vrfKeypair。如果该账户不存在,我们尚未初始化交换机 +`openLootbox` 从检查用户账户是否存在开始,如果不存在,则调用指令文件中的 `createInitSwitchboardInstructions` ,该文件会返回给我们`指令`和`vrfKeypair`。如果该账户不存在,我们尚未初始化交换机 ```tsx const openLootbox = async ( @@ -190,9 +188,7 @@ const openLootbox = async ( ``` -然后我们创建一个新的交易,添加指令并调用我们创建的 sendAndConfirmTransaction 。它以一个对象作为vrfKeypair的签名者。 - - +然后我们创建一个新的交易,添加指令并调用我们创建的 `sendAndConfirmTransaction` 。它以一个对象作为`vrfKeypair`的签名者。 ```tsx const transaction = new Transaction() @@ -203,11 +199,12 @@ const transaction = new Transaction() } ``` +让我们跳出逻辑,看看 `sendAndConfirmTransaction` 。首先,我们设定我们正在加载 `setIsConfirmingTransaction(true)` 。 +然后我们调用发送交易,但我们传递了选项,这是可选的,因为我们并不总是需要它。这是我们如何发送`vrfKeypair`的签名者,但我们并不总是这样做。 -让我们跳出逻辑,看看 sendAndConfirmTransaction 。首先,我们设定我们正在加载 setIsConfirmingTransaction(true) 。 -一旦确认,我们使用 await Promise.all 在我们调用 handleStateRefresh 和 fetchUpstreamState 的地方。后者作为一个属性传入,基本上是在stake组件上的fetch状态函数。 +一旦确认,我们使用 `await Promise.all` 在我们调用 `handleStateRefresh` 和 `fetchUpstreamState` 的地方。后者作为一个属性传入,基本上是在`stake`组件上的`fetch`状态函数。 ```tsx const sendAndConfirmTransaction = async ( @@ -248,7 +245,7 @@ const sendAndConfirmTransaction = async ( } ``` -现在回到 handleOpenLootbox 的else语句,这是处理账户存在的逻辑。所以我们设置了打开战利品箱指令并发送它们。然后调用 sendAndConfirmTransaction 。一旦确认,该函数将把is confirming设置为false,然后我们再次将其设置为true。 +现在回到 `handleOpenLootbox` 的`else`语句,这是处理账户存在的逻辑。所以我们设置了打开战利品箱指令并发送它们。然后调用 `sendAndConfirmTransaction` 。一旦确认,该函数将把`is confirming`设置为`false`,然后我们再次将其设置为`true`。 ```tsx ... @@ -269,7 +266,7 @@ const sendAndConfirmTransaction = async ( await sendAndConfirmTransaction(connection, walletAdapter, transaction) setIsConfirmingTransaction(true) ``` -最后,这是等待看到薄荷被存入战利品箱指针的逻辑,这样我们就可以兑换它。(这段代码只能偶尔工作,不要依赖它,如果可以的话请修复它)。 +最后,这是等待看到`mint`被存入战利品箱指针的逻辑,这样我们就可以兑换它。(这段代码只能偶尔工作,不要依赖它,如果可以的话请修复它)。 ```tsx const [lootboxPointerPda] = PublicKey.findProgramAddressSync( @@ -301,9 +298,7 @@ const sendAndConfirmTransaction = async ( } ``` -快速跳转到 /pages/stake.tsx 。我们做一个小修改,如果有 nftData 和 nftTokenAccount ,则显示战利品箱,并传入赌注账户、NFT代币账户,并调用fetchstate,将铸币地址作为上游属性传递。 - - +快速跳转到 `/pages/stake.tsx` 。我们做一个小修改,如果有 `nftData` 和 `nftTokenAccount` ,则显示战利品箱,并传入赌注账户、NFT代币账户,并调用`fetchstate`,将`mint address`作为上游属性传递。 ```ts @@ -319,7 +314,7 @@ const sendAndConfirmTransaction = async ( ``` -现在希望回顾一下 handleRedeemLoot ,这个过程更加简单明了。我们首先获取相关的令牌。然后使用我们的 retrieveItemFromLootbox 函数创建一个新的交易,然后发送并确认该交易。 +现在希望回顾一下 `handleRedeemLoot` ,这个过程更加简单明了。我们首先获取相关的令牌。然后使用我们的 `retrieveItemFromLootbox` 函数创建一个新的交易,然后发送并确认该交易。 ```tsx onst handleRedeemLoot: MouseEventHandler = useCallback( @@ -354,9 +349,9 @@ onst handleRedeemLoot: MouseEventHandler = useCallback( ) ``` -那是很多的内容,我们跳来跳去的,所以如果你需要参考整个文件的代码,请看[这里](https://github.com/jamesrp13/buildspace-buildoors/blob/solution-lootboxes/components/Lootbox.tsx?utm_source=buildspace.so&utm_medium=buildspace_project)。 +那是很多的内容,我们跳来跳去的,所以如果你需要参考整个文件的代码,请看[这里](https://github.com/jamesrp13/buildspace-buildoors/blob/solution-lootboxes/components/Lootbox.tsx)。 -唉,让我们来看看 GearItem 组件。这个组件相对简单一些,也要短得多。 +唉,让我们来看看 `GearItem` 组件。这个组件相对简单一些,也要短得多。 ```ts import { Center, Image, VStack, Text } from "@chakra-ui/react" @@ -416,23 +411,19 @@ export const GearItem = ({ 布局与上一个相当相似,但现在我们展示一张图片,以齿轮代币上的元数据作为来源。在其下方,我们展示您拥有的每个齿轮代币的数量。 +关于逻辑,我们传入该项作为代表代币铸币的`base58`编码字符串,以及您拥有的数量。 +在`useEffect`中,我们创建了一个`metaplex`对象。我们将 `item` 的字符串转换为公钥。然后调用`metaplex`来通过`mint`查找物品。我们得到了`nft`,调用`nft`的`uri`上的`fetch`方法,这样我们就可以获取到链下的元数据。我们将该响应转换为`json`s,并将其设置为元数据,这样我们就可以在返回调用中显示一个图像属性。 -关于逻辑,我们传入该项作为代表代币铸币的base58编码字符串,以及您拥有的数量。 - -在useEffect中,我们创建了一个metaplex对象。我们将 item 的字符串转换为公钥。然后调用metaplex来通过mint查找物品。我们得到了nft,调用nft的uri上的fetch方法,这样我们就可以获取到链下的元数据。我们将该响应转换为json,并将其设置为元数据,这样我们就可以在返回调用中显示一个图像属性。 - -回到 stake.tsx 文件。首先,我们为齿轮平衡添加一行状态。 +回到 `stake.tsx` 文件。首先,我们为齿轮平衡添加一行状态。 ```tsx const [gearBalances, setGearBalances] = useState({}) ``` -我们在fetchState内部调用它。 - -在获取状态中,我们将余额设置为空对象。然后循环遍历不同的齿轮选项,并获取与该铸币相关联的当前用户的ATA。这给了我们一个地址,我们用它来获取账户,并将特定齿轮铸币的余额设置为我们拥有的数字。在循环结束后,我们调用 setGearBalances(balances) 。 - +我们在`fetchState`内部调用它。 +在获取状态中,我们将余额设置为空对象。然后循环遍历不同的齿轮选项,并获取与该铸币相关联的当前用户的`ATA`。这给了我们一个地址,我们用它来获取账户,并将特定齿轮铸币的余额设置为我们拥有的数字。在循环结束后,我们调用 `setGearBalances(balances)` 。 所以在用户界面中,我们检查齿轮平衡的长度是否大于零,然后显示所有的齿轮相关内容,或者根本不显示。 @@ -478,7 +469,7 @@ const [gearBalances, setGearBalances] = useState({}) ``` -这就是检查和显示装备的全部内容。这是存储库中的代码,供您参考。 +这就是检查和显示装备的全部内容。这是[存储库](https://github.com/jamesrp13/buildspace-buildoors/blob/solution-lootboxes/components/GearItem.tsx)中的代码,供您参考。 接下来发生的事情取决于你。你可以决定要修复哪些错误,哪些你可以接受。将所有内容从本地主机移出并进行发布,这样你就可以分享一个公共链接。 diff --git a/docs/Solana-Co-Learn/module6/finishing-touches/the-final-pieces/README.md b/docs/Solana-Co-Learn/module6/finishing-touches/the-final-pieces/README.md index 2bd4f42f5..a42a8434d 100644 --- a/docs/Solana-Co-Learn/module6/finishing-touches/the-final-pieces/README.md +++ b/docs/Solana-Co-Learn/module6/finishing-touches/the-final-pieces/README.md @@ -11,16 +11,14 @@ sidebar_class_name: green 这是最后的冲刺!恭喜你到达这里!对每个人来说,这都是一段疯狂的旅程。无论你的NFT项目处于什么状态,都要深呼吸,给自己鼓励。你真棒! -现在,评估一下你目前所拥有的,并考虑一下为了让你的项目准备好进行交付,你可以做的最少工作量。如果这意味着暂时跳过Switchboard的事情,那就这样吧。 - - +现在,评估一下你目前所拥有的,并考虑一下为了让你的项目准备好进行交付,你可以做的最少工作量。如果这意味着暂时跳过`Switchboard`的事情,那就这样吧。 现在是时候将您的用户界面与您的战利品箱和装备指示连接起来,然后进行任何最后的润饰工作,然后将这个东西发货! 在我们的情况下,这意味着: -- 用 GearItem 和 Lootbox 组件替换我们在UI的那部分使用的模拟 ItemBox -- 添加一个文件,在这个文件中我们创建函数来: +- 用 `GearItem` 和 `Lootbox` 组件替换我们在UI的那部分使用的模拟 `ItemBox` +- 添加一个`instructions.ts`文件,在这个文件中我们创建函数来: - 创建所有必需的指令来初始化我们的战利品箱和交换机 - 创建打开战利品箱所需的所有说明 - 注意:这个有点激烈,哈哈 - 看看我们的解决方案代码,但也试试自己的方法 @@ -30,7 +28,7 @@ sidebar_class_name: green ## 解决方案代码 -我们的解决方案位于[Buildoors代码库](https://github.com/jamesrp13/buildspace-buildoors/tree/solution-lootboxes?utm_source=buildspace.so&utm_medium=buildspace_project)的 solution-lootboxes 分支上。在那里有一些提交使其与您上次看到的不同,所以如果您想查看所有更改,请确保从上周的[分支查看差异](https://github.com/jamesrp13/buildspace-buildoors/compare/solution-core-5...solution-lootboxes?expand=1&utm_source=buildspace.so&utm_medium=buildspace_project)。 +我们的解决方案位于[Buildoors代码库](https://github.com/CreatorsDAO/buildspace-buildoors/tree/solution-lootboxes)的 `solution-lootboxes` 分支上。在那里有一些提交使其与您上次看到的不同,所以如果您想查看所有更改,请确保从上周的[分支查看差异](https://github.com/CreatorsDAO/buildspace-buildoors/compare/solution-core-5...solution-lootboxes)。 有一些指南,但你可以先自己开始。祝你好运! @@ -48,7 +46,7 @@ sidebar_class_name: green 我们现在要深入研究一些代码的变动。让我们开始`/components/WorkspaceProvider.tsx`吧。 -只有一些小的变动,主要是为了加入交换机程序。 +只有一些小的变动,主要是为了加入`switchboard program.`。 有一个新的`useState`。 @@ -56,7 +54,7 @@ sidebar_class_name: green const [switchboardProgram, setProgramSwitchboard] = useState() ``` -然后我们加载交换机程序,并使用useEffect设置程序交换机,这样我们的工作区始终可以及时更新我们所需的所有程序。除非你是React专家,否则这可能会有些挑战,所以请随意深入参考这段代码。 +然后我们加载`switchboard program`,并使用`useEffect`设置`the program switchboard`,这样我们的工作区始终可以及时更新我们所需的所有程序。除非你是React专家,否则这可能会有些挑战,所以请随意深入参考这段代码。 ```tsx async function program() { @@ -76,7 +74,7 @@ useEffect(() => { }, [connection]) ``` -好的,接下来我们进入 instructions.ts 文件夹中的 utils 文件,这是一个新文件。这里有两个公共函数,分别是 createOpenLootboxInstructions 指令和 createInitSwitchboardInstructions 指令。后者用于打包交换机程序的初始化内容,并初始化抽奖箱程序中的用户。 +好的,接下来我们进入 `instructions.ts` 文件夹中的 `utils` 文件,这是一个新文件。这里有两个公共函数,分别是 `createOpenLootboxInstructions` 指令和 `createInitSwitchboardInstructions` 指令。后者用于打包交换机程序的初始化内容,并初始化抽奖箱程序中的用户。 ```tsx export async function createOpenLootboxInstructions( @@ -114,7 +112,7 @@ export async function createOpenLootboxInstructions( } ``` -进一步往下,有一个 getAccountsAndData 函数,它接受四个字段,正如你所见,对于最后一个字段,你需要事先生成或获取vrf账户。这个函数的作用是获取一些账户、增加和其他数据,将它们打包起来,并作为一个对象返回。 +进一步往下,有一个 `getAccountsAndData` 函数,它接受四个字段,正如你所见,对于最后一个字段,你需要事先生成或获取`vrf`账户。这个函数的作用是获取一些账户、增加和其他数据,将它们打包起来,并作为一个对象返回。 ```tsx async function getAccountsAndData( @@ -198,7 +196,7 @@ interface AccountsAndDataSuperset { } ``` -让我们深入了解 createInitSwitchboardInstructions 。它首先生成一个vrf密钥对,然后调用 getAccountsAndData 来获取我们所需的所有账户。然后,通过 initSwitchboardLootboxUser ,它组装指令。然后返回指令,以及用于签名的vrf密钥对。 +让我们深入了解 `createInitSwitchboardInstructions` 。它首先生成一个`vrf`密钥对,然后调用 `getAccountsAndData` 来获取我们所需的所有账户。然后,通过 `initSwitchboardLootboxUser` ,它组装指令。然后返回指令,以及用于签名的`vrf`密钥对。 ```tsx export async function createInitSwitchboardInstructions( @@ -229,7 +227,7 @@ export async function createInitSwitchboardInstructions( } ``` -关于 initSwitchboardLootboxUser ,我们首先获得一个PDA和状态提升。 +关于 `initSwitchboardLootboxUser` ,我们首先获得一个`PDA`和`state bump`。 ```tsx async function initSwitchboardLootboxUser( @@ -274,7 +272,7 @@ const txnIxns: TransactionInstruction[] = [ ``` -然后我们调用create account来创建vrf账户。 +然后我们调用`create account`来创建vrf账户。 ```tsx // request system program to create new account using newly generated keypair for VRF account @@ -290,7 +288,7 @@ const txnIxns: TransactionInstruction[] = [ }), ``` -然后我们使用交换机程序方法进行vrf初始化,其中我们提供了消耗随机性回调函数。 +然后我们使用`switchboard program `方法进行`vrf`初始化,其中我们提供了消耗随机性回调函数。 ```tsx // initialize new VRF account, included the callback CPI into lootbox program as instruction data @@ -334,7 +332,7 @@ await switchboardProgram.methods .instruction(), // initialize switchboard permission account, required account ``` -接下来我们使用交换机来调用权限初始化。 +接下来我们使用`switchboard`来调用权限初始化。 ```tsx await switchboardProgram.methods @@ -350,9 +348,7 @@ await switchboardProgram.methods .instruction(), ``` -最后,我们将我们的战利品箱计划称为init user,并返回指示,这将由调用者打包成交易。 - - +最后,我们将我们的战利品箱计划称为`init user`,并返回指示,这将由调用者打包成交易。 ```tsx await lootboxProgram.methods @@ -373,7 +369,7 @@ await lootboxProgram.methods } ``` -最后,让我们回顾一下 createOpenLootboxInstructions 。首先,我们获取用户状态PDA,我们必须实际获取该账户,以便我们可以从中提取vrf密钥对。 +最后,让我们回顾一下 `createOpenLootboxInstructions` 。首先,我们获取用户状态`PDA`,我们必须实际获取该账户,以便我们可以从中提取`vrf`密钥对。 ```tsx export async function createOpenLootboxInstructions( @@ -393,9 +389,7 @@ export async function createOpenLootboxInstructions( const state = await lootboxProgram.account.userState.fetch(userStatePda) ``` -在这里,我们称之为 getAccountsAndData 来获取我们所需的所有账户。接下来是 createAllOpenLootboxInstructions ,我们将深入探讨。 - - +在这里,我们称之为 `getAccountsAndData` 来获取我们所需的所有账户。接下来是 `createAllOpenLootboxInstructions` ,我们将深入探讨。 ```tsx const accounts = await getAccountsAndData( @@ -438,7 +432,7 @@ async function createAllOpenLootboxInstructions( ) ``` -接下来我们获得与BLD相关的 stakeTokenAccount ,因此您可以使用BLD代币来换取开启战利品箱。然后是质押账户,以确保您通过质押获得足够的BLD来开启战利品箱。 +接下来我们获得与`BLD`相关的 `stakeTokenAccount` ,因此您可以使用`BLD`代币来换取开启战利品箱。然后是质押账户,以确保您通过质押获得足够的`BLD`来开启战利品箱。 ```tsx // user BLD token account, used to pay BLD tokens to call the request randomness instruction on Lootbox program @@ -471,7 +465,7 @@ let instructions: TransactionInstruction[] = [] } ``` -然后我们推送一个转账指令,将SOL转移到wrapped SOL。然后是一个同步wrapped SOL余额的指令。 +然后我们推送一个转账指令,将SOL转移到`wrapped SOL`。然后是一个同步`wrapped SOL`余额的指令。 ```tsx // transfer SOL to user's own wSOL token account diff --git a/docs/Solana-Co-Learn/module6/finishing-touches/the-last-ship/README.md b/docs/Solana-Co-Learn/module6/finishing-touches/the-last-ship/README.md index 647c8113e..54f2d3cdd 100644 --- a/docs/Solana-Co-Learn/module6/finishing-touches/the-last-ship/README.md +++ b/docs/Solana-Co-Learn/module6/finishing-touches/the-last-ship/README.md @@ -1,18 +1,19 @@ --- sidebar_position: 108 -sidebar_label: 🏁 The last ship 最后一艘船 +sidebar_label: 🏁 最后一艘船 sidebar_class_name: green --- -# 🏁 The last ship 最后一艘船 +# 🏁 最后一艘船 天哪,你终于做到了 🫡 非常感谢您参与我们的内测计划!没有您的支持,这一切都不可能实现。 -来自buildspace团队的最后几件事情 +来自 `706 & RustyCab` 团队的最后几件事情 -- 请将您的提交放入展示频道!我们想看看您建造了什么!! -- 快发个推文吧!你做了大量的工作,全世界都应该知道! +1. 请将您的提交放入展示频道!我们想看看您建造了什么!! + +2. 快发个推文吧!你做了大量的工作,全世界都应该知道! 你现在正式在玻璃上冲浪——我们在那里见。