测试网
测试网是一个隔离的网络,专门用来测试各种可能的功能提供给开发者们。
在测试网上需要用到测试用的TON coins,这些并没有实际价值,所以你不需要担心花费真金白银来购买。有很多faucet可以用,比如官方的testnet giver Telegram bot.现在对于初学者,我们会从如何在测试网上部署合约开始。
测试币自动发放机器人会要求你提供一个地址,以供它发放一些testcoin,所以在此之前你需要一个钱包地址来接受。Tonhub和Tonkeeper都是可选项,并且都集成了TON测试网功能。以Tonhub为例,IOS可以从苹果商店中下载下来。
当你安装好TONhub后,就可以复制测试网地址来接受test TONcoin了。
部署脚本
现在来创建一个新的脚本文件在scripts文件夹下——deploy.ts,和之前所说一样,部署一个合约需要:
- 计算未来的合约地址
- 合成合约的初始状态
- 合成一条能携带初始状态的消息
- 发送消息到第一步中已计算出的链上合约地址上
在发送消息前部署脚本的代码:
import { hex } from '../build/main.compiled.json'; import { beginCell, Cell, contractAddress, StateInit, storeStateInit, toNano, } from '@ton/core'; async function deployScript() { const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0]; const dataCell = new Cell(); const stateInit: StateInit = { code: codeCell, data: dataCell, }; const stateInitBuilder = beginCell(); storeStateInit(stateInit)(stateInitBuilder); const stateInitCell = stateInitBuilder.endCell(); const address = contractAddress(0, { code: codeCell, data: dataCell, }); } deployScript();
StateInit 和 storeStateInit函数是头一次出现,其中storeStateInit是由@ton/core提供的用来创建Cell的函数,可以将stateInit存在里面。
const stateInit: StateInit = { code: codeCell, data: dataCell, }; const stateInitBuilder = beginCell(); storeStateInit(stateInit)(stateInitBuilder); const stateInitCell = stateInitBuilder.endCell();
其中设计到Builder到概念同样很重要,他是成功创建FunC合约并通过Typescript操作的关键。如上所示,我们利用beginCell函数返回了一个Builder。
我们将stateInit传进storeStateInit,然后返回一个可以写入builder的函数,再执行这个函数传入builder中。
此时我们已经有了一个写好stateInit的builder,只需run一下 .endCell()就可以闭合builder进一个完整的cell中。
我们也可以选择手动创建这样子的cell,例如:
const stateInitCell = beginCell() .storeBit(false) // split_depth - Parameter for the highload contracts, defines behaviour of splitting into multiple instances in different shards. Currently StateInit used without it. .storeBit(false) // special - Used for invoking smart contracts in every new block of the blockchain. Available only in the masterchain. Regular user's contracts used without it. .storeMaybeRef(codeCell) // code - Contract's serialized code. .storeMaybeRef(dataCell) // data - Contract initial data. .storeUint(0, 1) // library - Currently StateInit is used without libs .endCell();
想要对Initstate有更深的的了解,可以参考这篇document。
创建携带StateInit的消息
为了能发送消息,首先我们需要用到之前创建好的Tonhub钱包。钱包有一个API可以允许其进行深度链接,意味着我们可以创建一个包含了所有发送一条消息所需要的参数的link。创建完成LINK后在TONHUB钱包中打开,并签署真正的交易来发送消息,执行这些步骤还需要一个qs库来帮助我们创建包含复杂参数的url。
yarn add qs @types/qs --dev
由于我们呢的Tonhub钱包是在移动端上的,link是在桌面端的,只需生成一个该link的qrcode二维码,就可以发送部署消息了。这步还需要qrcode-terminal库来完成。
yarn add qrcode-terminal @types/qrcode-terminal --dev
导入以上两个第三方库之后,代码应该长这样:
import { hex } from "../build/main.compiled.json"; import { beginCell, Cell, contractAddress, StateInit, storeStateInit, toNano } from "@ton/core"; import qs from "qs"; import qrcode from "qrcode-terminal"; async function deployScript() { const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0]; const dataCell = new Cell(); const stateInit: StateInit = { code: codeCell, data: dataCell, }; const stateInitBuilder = beginCell(); storeStateInit(stateInit)(stateInitBuilder); const stateInitCell = stateInitBuilder.endCell(); const address = contractAddress(0, { code: codeCell, data: dataCell, }); let link = `https://tonhub.com/transfer/` + address.toString({ testOnly: true, }) + "?" + qs.stringify({ text: "Deploy contract", amount: toNano(1).toString(10), init: stateInitCell.toBoc({ idx: false }).toString("base64"), }); qrcode.generate(link, { small: true }, (code) => { console.log(code); }); } deployScript();
正如之前做过的那样,添加一些console.log让代码更可读:
import { hex } from "../build/main.compiled.json"; import { beginCell, Cell, contractAddress, StateInit, storeStateInit, toNano, } from "ton"; import qs from "qs"; import qrcode from "qrcode-terminal"; async function deployScript() { console.log( "=================================================================" ); console.log("Deploy script is running, let's deploy our main.fc contract..."); const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0]; const dataCell = new Cell(); const stateInit: StateInit = { code: codeCell, data: dataCell, }; const stateInitBuilder = beginCell(); storeStateInit(stateInit)(stateInitBuilder); const stateInitCell = stateInitBuilder.endCell(); const address = contractAddress(0, { code: codeCell, data: dataCell, }); console.log( `The address of the contract is following: ${address.toString()}` ); console.log(`Please scan the QR code below to deploy the contract:`); let link = `https://tonhub.com/transfer/` + address.toString({ testOnly: true, }) + "?" + qs.stringify({ text: "Deploy contract", amount: toNano(1).toString(10), init: stateInitCell.toBoc({ idx: false }).toString("base64"), }); qrcode.generate(link, { small: true }, (code) => { console.log(code); }); } deployScript();
完成后在package.json中添加脚本捷径:
{ ... our previous package.json keys "scripts": { ... previous scripts keys "deploy:testnet": "yarn compile && ts-node ./scripts/deploy.ts" } }
在terminal中run(yarn deploy:testnet)就会发现终端中出现了一个qrcode,用Tonhub钱包扫描该二维码,确保扫描前已经领取过了TON testcoin,账户余额不为0,然后签署交易。
一旦完成,我们又该如何验证确实成功部署在测试网上了呢?常用blockchain exploer的人应该熟悉,TON中一样有类似etherum Scan的网站,例如https://tonapi.io/,他也有测试网版本,在上面就可以检查自己的合约是否已经成功部署了。
将智能合约的地址输入bar中,如果每一步都没出错,理论上出现的应该是一笔1 ton的转账。