TON:用Blueprints来部署合约
🥑

TON:用Blueprints来部署合约

Blueprint是由TonTech团队维护,并获得TON基金会的官方支持的。
我从头开始创建自定义脚本,以确保理解在Blueprint生成项目的过程中到底发生了什么。
首先,在开始每个新项目时都使用以下命令:
npm create ton@latest
该命令将使用Blueprint生成一个新项目,其中包含一些基础的模块化代码,同时涵盖了合约开发中的一些必要组件。
在这一篇中,我将略微更新项目的编译和部署方式,使其使用从Blueprint导入的组件。

将编译过程委托给Blueprint

首先更新package.json文件。从现在开始,只需保留一个脚本——test,而编译和部署将由从Blueprint导入的组件处理。
package.json文件的脚本部分现在应如下所示:
"scripts": { "test": "jest" }
然而,如果现在运行yarn test命令,它将只是在未预编译合约的情况下运行测试。所以需要使用Blueprint的编译套件:
yarn add @ton/blueprint --dev
tests/main.spec.ts文件中需要进行一些重要的更新。这是之前的样子(这里只引用了实际测试之前的部分):
import { Cell, toNano } from "ton-core"; import { hex } from "../build/main.compiled.json"; import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox"; import { MainContract } from "../wrappers/MainContract"; import "@ton/test-utils"; describe("main.fc contract tests", () => { let blockchain: Blockchain; let myContract: SandboxContract<MainContract>; let initWallet: SandboxContract<TreasuryContract>; let ownerWallet: SandboxContract<TreasuryContract>; beforeEach(async () => { blockchain = await Blockchain.create(); initWallet = await blockchain.treasury("initWallet"); ownerWallet = await blockchain.treasury("ownerWallet"); const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0]; myContract = blockchain.openContract( await MainContract.createFromConfig( { number: 0, address: initWallet.address, owner_address: ownerWallet.address, }, codeCell ) ); }); // ... the rest of testing code }
我将对其进行3处更新:
  1. @ton-blueprint库中导入compile函数
  1. 实现Jest的beforeAll钩子来编译我们的代码并为其他钩子和测试提供代码单元
  1. 更新beforeEach钩子以使用beforeAll钩子提供的代码单元
以下是代码变更后的样子:
// ...other library imports import { compile } from "@ton/blueprint"; describe("main.fc contract tests", () => { let blockchain: Blockchain; let myContract: SandboxContract<MainContract>; let initWallet: SandboxContract<TreasuryContract>; let ownerWallet: SandboxContract<TreasuryContract>; let codeCell: Cell; beforeAll(async () => { codeCell = await compile("MainContract"); }); beforeEach(async () => { blockchain = await Blockchain.create(); initWallet = await blockchain.treasury("initWallet"); ownerWallet = await blockchain.treasury("ownerWallet"); myContract = blockchain.openContract( await MainContract.createFromConfig( { number: 0, address: initWallet.address, owner_address: ownerWallet.address, }, codeCell ) ); }); // ... the rest of testing code }
进行这些更改是为了习惯在运行npm create ton@latest时生成的代码,将编译过程委托给Blueprint库。
还需要为Blueprint提供一项额外的配置——编译器配置。为此,只需在wrappers文件夹中创建一个新文件,命名为MainContract.compile.ts。以下是该文件的内容:
import { CompilerConfig } from "@ton/blueprint"; export const compile: CompilerConfig = { targets: ["contracts/main.fc"], };
此时删除编译脚本文件(scripts/compile.ts)并在项目根目录中运行yarn test,将看到我们的测试现在能够正常执行。

将部署过程委托给Blueprint

接下来更新部署脚本,我将使用包装器MainContract及其方法.createFromConfig。这样可以在部署合约之前设置合约的初始状态。
它会通过交互式方式让我们选择网络(测试网/主网)以及用于部署合约的钱包类型。这一功能在频繁开发和部署时非常便利。
在更新部署脚本之前,需要在包装器上创建一个新方法,称为sendDeploy。我需要使用包装器与合约交互。代码如下:
async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, body: beginCell().endCell(), }); }
部署合约就是将其初始数据和代码发送到其预定地址。之前手动组的这些数据,以便深入了解其工作原理。现在,为了优化,可以将此任务委托给我们的包装器和Blueprint。
更新代码,使其符合Blueprint的功能。
以下是新的scripts/deploy.ts文件的样子:
import { address, toNano } from "ton-core"; import { MainContract } from "../wrappers/MainContract"; import { compile, NetworkProvider } from "@ton/blueprint"; export async function run(provider: NetworkProvider) { const myContract = MainContract.createFromConfig( { number: 0, address: address("kQDU69xgU6Mj-iNDHYsWWuNx7yRPQC_bNZNCpq5yVc7LiE7D"), owner_address: address( "kQDU69xgU6Mj-iNDHYsWWuNx7yRPQC_bNZNCpq5yVc7LiE7D" ), }, await compile("MainContract") ); const openedContract = provider.open(myContract); openedContract.sendDeploy(provider.sender(), toNano("0.05")); await provider.waitForDeploy(myContract.address); }
这比之前的简洁,现在可以使用wrapper中的同一个.createFromConfig方法来初始化要部署的合约,并通过传递给它的配置对象设置初始状态数据。
配置对象的内容有两点需要解释:
  1. 合约初始数据必须包含三个参数——当前计数器值(number)、最近的发送者(address)和合约的“所有者”地址,即能够提取资金的人。由于要在链上使用这个合约,我设置了我的实际测试网地址作为两个字段的值。这将使我以后能够提取资金。
  1. address函数帮助我们将字符串地址解析为配置对象所需的Address类型。
核心部署功能由类型为NetworkProvider的provider处理,它会在Blueprint触发部署脚本时传递给run函数。
如果你希望你的脚本能够与Blueprint一起工作,那么所有脚本都必须导出run函数。
Let's jump back to .sendDeploy method of our wrapper for a second. Have a look at body param. You can see that we are sending an empty cell as message body. As of the logic of our contract, if the message body has no operation code set to it - the message will be bounced even though the contract will be successfully deployed. You will see this behaviour in a few moments.

使用Blueprint部署合约

回到项目根目录并运行以下命令:
yarn blueprint run
运行此命令后,你可以期望在命令行中看到如下内容:
$ yarn blueprint run yarn run v1.22.11 ? Choose file to use (Use arrow keys) ❯ deploy onchaintest
Blueprint通过命令行提示我们选择要运行的脚本。目前我们仍然有onchaintest.ts脚本,所以它也会被提供给我们执行,因为Blueprint捕获了scripts文件夹中所有可用的脚本。此时,我暂时不会创建任何链上测试,目前可以简单地删除scripts/onchaintest.ts文件。
选择deploy脚本。
现在提示选择网络:
yarn blueprint run yarn run v1.22.11 ? Choose file to use (Use arrow keys) ? Choose file to use deploy ? Which network do you want to use? (Use arrow keys) ❯ mainnet testnet
选择网络testnet
yarn blueprint run yarn run v1.22.11 ? Choose file to use (Use arrow keys) ? Choose file to use deploy ? Which network do you want to use? ? Which network do you want to use? testnet ? Which wallet are you using? (Use arrow keys) ❯ TON Connect compatible mobile wallet (example: Tonkeeper) Create a ton:// deep link Tonhub wallet Mnemonic
选择Tonhub钱包应用程序。
要求扫描二维码并授权你的应用与钱包交互(请求交易)。
yarn blueprint run yarn run v1.22.11 ? Choose file to use (Use arrow keys) ? Choose file to use deploy ? Which network do you want to use? (Use arrow keys) ? Which network do you want to use? mainnet ? Which wallet are you using? ? Which wallet are you using? Tonhub wallet ton://connect/GzhvQ-zwLhYNxzlEPEf-hP63kgR_0_O8vXsM8mSqQ-0?endpoint=connect.tonhubapi.com Connected to wallet at address: EQC7zjln0_fghMQg0A-ZhYFar3DU1bDW9A4Vi5Go5uu-tAHe
扫描二维码并在你的应用中授权后,你将被请求在Tonhub应用中签署一笔交易。完成后,你将在命令行中看到以下输出:
yarn blueprint run yarn run v1.22.11 ? Choose file to use (Use arrow keys) ? Choose file to use deploy ? Which network do you want to use? ? Which network do you want to use? testnet ? Which wallet are you using? ? Which wallet are you using? Tonhub wallet Connected to wallet at address: EQDU69xgU6Mj-iNDHYsWWuNx7yRPQC_bNZNCpq5yVc7LiPVJ Contract deployed at address EQCS7PUYXVFI-4uvP1_vZsMVqLDmzwuimhEPtsyQKIcdeNPu You can view it at https://testnet.tonscan.org/address/EQCS7PUYXVFI-4uvP1_vZsMVqLDmzwuimhEPtsyQKIcdeNPu ✨ Done in 19.84s.
恭喜!合约部署成功了。