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处更新:
- 从
@ton-blueprint
库中导入compile
函数
- 实现Jest的
beforeAll
钩子来编译我们的代码并为其他钩子和测试提供代码单元
- 更新
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
方法来初始化要部署的合约,并通过传递给它的配置对象设置初始状态数据。配置对象的内容有两点需要解释:
- 合约初始数据必须包含三个参数——当前计数器值(
number
)、最近的发送者(address
)和合约的“所有者”地址,即能够提取资金的人。由于要在链上使用这个合约,我设置了我的实际测试网地址作为两个字段的值。这将使我以后能够提取资金。
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.
恭喜!合约部署成功了。