English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french

简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE คนไทย Français русский

回答

收藏

3.2 设置编译流程

开源社区 开源社区 8984 人阅读 | 0 人回复 | 2025-03-06

本帖最后由 riyad 于 2025-3-7 00:19 编辑 2 u* `7 }3 ^6 n7 p- }1 ]7 B

1 ^/ c9 Y4 z" A: Z6 P- _
本课的目的是建立一个能够编译智能合约示例的本地项目。我们现在还不打算编写任何 FunC。我们只是在准备搭建我们的本地环境。这部分内容以后可以在所有项目中重复使用。

/ u" g" k8 ?1 ^: \9 B  f& f
首先,请确保您拥有三样东西:
  • Node.js (16.15.0 或更高版本) 安装说明 here ( https://nodejs.org/)  运行命令 node -v 在终端中验证您的安装
  • 软件包管理器 - 它可能已经与 Node.js 安装在一起,但请确保您已经安装了 Node.js。在本课中,我们将使用 Yarn,但您也可以自行选择使用 Yarn, 但您也可以选择使用 (ex. npm)
  • 带有 FunC 和 TypeScript 的集成开发环境 支持 我们建议使用 Visual   Studio CodeFunC plugin 已安装。如果您使用的是 IntelliJ,以下是相应的链接 FunC plugin
    9 f; S- r" Y* }( o, a' b+ p& D! G
满足上述要求后,我们就可以开始了!

$ @" N3 h  x5 @) ]1 f: V建立项目。
首先为我们的项目创建一个文件夹
  1. mkdir my_first_contract && cd my_first_contract3 T/ |. b$ i+ |/ l; O
复制代码
让我们启动 package.json 文件. 我要用 yarn, 但如果你觉得使用 npm 更好,你可以自由选择。
  1. yarn init! R2 F; e( l* z5 i1 J7 ]
复制代码
系统会提示你输入一些参数,但你只需在每个提示符下点击 Enter 按钮即可。完成后,项目目录下的 package.json 文件将包含以下默认内容:
  1. {
    ) r& {/ V, }' A, s) [- n4 Q0 i" z7 U
  2. 6 w6 S6 J6 C* D
  3.   "name": "my_first_contract",9 Q& x. N; @8 Y3 w+ a: b

  4. 7 v, ^7 H2 o1 x+ s
  5.   "version": "1.0.0",
    ; {: g' V' D1 x- f- q' a! w

  6. 2 T4 w7 y9 |$ y8 d. H
  7.   "main": "index.js", //we don't really need this line, feel free to remove it
    . H" C- @/ {  t; u; U' [: ^

  8. , g4 ^$ U- s- O
  9.   "license": "MIT"
    3 z  k+ S3 P8 j# d% I

  10. 0 [; X0 o( t0 {  x
  11. }
复制代码
现在,让我们安装以下 4 个库:
这些都是与 TypeScript 相关的库。在本课程中,我们不会深入探讨 TypeScript 本身的工作原理。
  1. yarn add typescript ts-node @types/node @swc/core --dev
    0 a0 X. M$ E  R" H9 X$ n
复制代码
我们创建一个 tsconfig.json 文件,并在其中添加以下配置:
  1. {- l! n, F6 `0 W1 c3 ]8 _

  2. * y& L; n  P, L: k0 S) t9 ]
  3.   "compilerOptions": {$ S% T; l+ w! u9 }& @

  4. % e) D' F( g; `& C( ~* A9 K
  5.     "target": "es2020",
    ; B) b$ q' x( l$ |$ q. V

  6. : t+ W6 q$ H& |, }" c
  7.     "module": "commonjs",
    8 ~6 C- k4 ~4 O% d6 K; |* r* [; |

  8. 1 W1 |, c5 [* V7 q% o% Z
  9.     "esModuleInterop": true,
    * K. {+ ?5 a: ~3 J; I; g* T
  10. 9 v, P& T# b( J9 p" t
  11.     "forceConsistentCasingInFileNames": true,
    # E  z7 D1 H  M# {3 a

  12. * y% p. h: ]+ f! Q
  13.     "strict": true,
    " K7 t2 W* A; z7 [

  14. 1 }' p# n, G' v* @" O
  15.     "skipLibCheck": true,5 M9 k8 O; S0 O# @/ r/ s
  16. ; K0 r$ f* _# |4 b7 T7 K
  17.     "resolveJsonModule": true
    " P* S+ V. l8 G$ M" y7 l

  18. 7 K8 t* ?  \- F2 M2 c$ u1 Q* x
  19.   },9 k! J- @% z+ Z0 |4 w; d& z9 B

  20. 9 C- r- E6 R3 J  D
  21.   "ts-node": {
    ) }6 O9 w6 S0 @1 z. T% Q) h6 h8 R
  22. , j" Z8 c9 ^0 X  P; q6 C
  23.     "transpileOnly": true,: T8 J1 g, X! r( ~5 {

  24. # C. K/ H; J& X9 _0 Y/ U
  25.     "transpiler": "ts-node/transpilers/swc"
    . x9 T, H$ b( X- N: \, a0 t
  26. * q; d. V2 ]! v) O5 s& w
  27.   }
    8 K0 ]; a' s6 `: @
  28. $ N, u8 G9 A: |& R
  29. }
复制代码
实际上,我们还需要三个与 TON 有关的 lib,它们是:
  • ton-core - 实现 TON 区块链底层基元的核心库。
  • ton-crypto - 用于为 TON 区块链构建应用程序的加密基元。
  • @ton-community/func-js - TON FunC 编译器
    * l- d" A  b9 D1 N/ d
) W, R% _% _  a9 }' J
  1. yarn add @ton/core ton-crypto @ton-community/func-js --dev+ R! {2 Q1 r8 C9 B9 Q" x7 o0 ?" h
复制代码
FunC 代码示例
现在,我们将创建一个包含最小 FunC 代码示例的文件,然后编写一个可以编译它的脚本。
我们创建一个 contracts 文件夹,并在其中创建一个 FunC 文件(main.fc):
  1. mkdir contracts && cd contracts && touch main.fc1 Z2 w. L) u9 d6 N
复制代码
打开 main.fc 文件进行编辑,并插入以下示例 FunC 代码:
  1. () recv_internal(int msg_value, cell in_msg, slice in_msg_body) impure {& X" i3 T/ ^( V, [8 u. Y

  2. / d0 p2 \- W, l+ x
  3. }
复制代码
您已经知道 TON 智能合约可以接收两种信息,如果您不清楚这些信息是什么,请参阅第 1 章。这些简单的代码就足够我们编写一个编译器脚本了。我们开始吧!
, a: E; E6 |  `- V, Q9 s& {: H; Z" h7 {" j, ?
编写编译脚本
在项目根目录下创建 scripts 文件夹,并在 scripts 文件夹下新建文件 compile.ts:
  1. mkdir scripts && cd scripts && touch compile.ts$ U5 r) Q6 {' y
复制代码
我们已经有了一个 compile.ts 文件,但还是让它在我们完成代码后方便运行吧。让我们在 package.json 文件中创建一个脚本快捷方式。只需添加以下脚本键即可:
  1. {
    7 Y0 O; P, u% b! E
  2.    //...your previous package.json contents+ Q" c+ T1 d1 u* [- g* x5 o. y
  3.    "scripts": {( Y" z% X! L1 ^/ y
  4. "compile": "ts-node ./scripts/compile.ts"9 h3 d) @( x8 r* e' o, o6 d: \) m
  5.    }
      ]4 O, g5 r7 S
  6. }
复制代码
现在在编辑器中打开 scripts/compile.ts 文件,开始编写编译脚本。我们将一步一步地添加代码,并附带说明,因此在本节结束时,你将拥有编译脚本的完整代码。
首先,我们要导入:
  • fs 用于处理文件
  • process 来控制脚本的执行过程
  • Cell 构造函数(我们合约的字节码将存储为 Cell)
  • compileFunc - 实际编译功能

    & y4 d" A( o: a  z4 @7 Z' x5 q; `4 d

6 P( q% o+ G/ ]8 `' a
  1. import * as fs from "fs";
    ! U) u, C, R3 w! r1 o
  2. import process from "process";
    2 w2 V. n- w0 K6 {. m
  3. import { Cell } from "@ton/core";
    $ Q$ g2 {1 o2 \6 w1 y  ^" O
  4. import { compileFunc } from "@ton-community/func-js";
复制代码
我们将有一些异步代码,因此让我们创建一个异步函数,在内部运行这些代码:
" F% ]& Q9 ]! h" q3 n* y
  1. import * as fs from "fs";
    & k* z, v( w: Q% \
  2. import process from "process";
    5 \0 x5 E2 e7 K; \
  3. import { Cell } from "@ton/core";
    5 P5 U0 s+ w+ [( T. K( S
  4. import { compileFunc } from "@ton-community/func-js";
    6 L! R: {6 [  g' t7 v$ y4 z% F
  5. 2 D! B2 p, Y8 W* Q4 p
  6. async function compileScript() {
    ( C. R( A" E  @5 L$ _& G7 U

  7. : l) j* L) w$ ?
  8. }
    - }3 y' V) G3 {* H. Y
  9. * r& [$ G5 @& c) [; K/ l. R
  10. compileScript();
复制代码
现在,我们将样本合约的文件名传入 compileFunc 函数,如果结果状态为错误,则退出脚本:

; H6 Z$ d* X* T# y6 T7 ~* o
  1. import * as fs from "fs";3 I# R) O0 k9 P- c6 l9 B' a
  2. import process from "process";
      g* r) U- N( u/ m9 `& _: ?, A
  3. import { Cell } from "@ton/core";
    # O, [) M' y) F* E8 s
  4. import { compileFunc } from "@ton-community/func-js";( W" S$ w5 o2 R: j9 z

  5. & M2 N( i5 @/ Y" H5 Y- {/ l
  6. async function compileScript() {
    9 t0 p5 m$ ]- y9 G, g

  7. . ]* X7 U# Y; z- q& H5 T6 V
  8.   const compileResult = await compileFunc({- W8 s: g7 w) P% y% ?; g
  9.     targets: ["./contracts/main.fc"],
    " B( T0 [8 R% D- s6 q, v9 t
  10.     sources: (x) => fs.readFileSync(x).toString("utf8"),
    9 g. m5 F2 f$ E3 c' A
  11.   });. m; V6 [0 J! p/ r# X' {6 q
  12. 8 l5 ]+ a: x# j" T0 [6 @
  13.   if (compileResult.status === "error") {
    : s( L' z" |, C
  14.     process.exit(1);
    1 s0 s, Z  t9 V9 ?5 d  E) I
  15.   }
    ; u# [+ U; M3 b! M; V, _
  16. }
    5 `9 s  A. l( P; W9 d
  17. compileScript();
复制代码
太棒了!从技术上讲,你已经可以进入我们项目的根目录,运行  yarn compile 指挥部. 但如果这样做,就无法看到编译结果。让我们将编译结果保存到文件夹 build 在我们项目的根目录下(确保先创建了它)。
编译结果将是一个 BOC(Body of Cell)base64 字符串,但如果我们想在本地进一步使用这个编译后的合约(在编写测试时),就需要构建一个包含该 BOC 的 Cell,并将其存储起来以备日后使用。
Cell 构造函数有一个 .fromBoc 方法,该方法希望接收一个缓冲区,因此我们将向其提供一个 BOC base64 字符串缓冲区。一旦我们从 BOC 构建了一个cell,我们就要为这个cell创建一个十六进制表示法,并将其存储到一个 JSON 文件中。这就是cell构建和转换命令的样子:
  1. Cell.fromBoc(Buffer.from(compileResult.codeBoc, "base64"))[0].toBoc() .toString("hex")- |& Z" N) P% v% e& V
复制代码
现在,我们将其放入脚本,并使用 fs.writeFileSync 将结果保存到 JSON 文件中:
  1. import * as fs from "fs";0 R+ V6 u+ @& S
  2. import process from "process";
    ( p. [8 n$ w+ y% p
  3. import { Cell } from "@ton/core";) }+ E2 M8 k* p: g. f% G6 @
  4. import { compileFunc } from "@ton-community/func-js";$ P5 U' C0 ]( i# ]" ~' b* x6 C2 r
  5. 4 T. N( j+ F5 h8 f2 g
  6. async function compileScript() {9 ~+ ?# Y, g8 H: Q4 q$ h5 m6 g+ I

  7. / r' [  I$ A. J4 ?9 x7 i; x- \( a
  8.   const compileResult = await compileFunc({* \# ^! K: b) v5 f2 t& k7 g6 N5 _9 q
  9.     targets: ["./contracts/main.fc"],
    6 l. H& {* P8 n+ \* d  q
  10.     sources: (x) => fs.readFileSync(x).toString("utf8"),' a7 n3 W, [& H4 @
  11.   });
    8 M2 n- g' H7 j

  12. 3 j2 i( S* p( k! u7 e: v4 m
  13.   if (compileResult.status === "error") {
    4 M& X3 A/ [! W
  14.     process.exit(1);
    0 ?; g1 L, {9 {9 x7 _1 A
  15.   }
    + u  R5 [3 ^, W

  16. 8 ^* i9 R; H% r# j0 Y
  17.   const hexArtifact = `build/main.compiled.json`;
    2 X, b- y3 x' C0 T  M$ b- W
  18. - [& E) ~* W2 X* s' s- U& A: k& v
  19.   fs.writeFileSync(' y% ?3 L# d* ^$ E
  20.     hexArtifact,
    + ^7 m" N0 s! ^, T/ i( ?
  21.     JSON.stringify({
    $ G7 h; f6 O1 F5 l. q# h( N
  22.       hex: Cell.fromBoc(Buffer.from(compileResult.codeBoc, "base64"))[0]
    / d" i+ I& X( f% }& I. U
  23.         .toBoc()* ?% O; g5 ~% D6 a8 n
  24.         .toString("hex"),
    : K2 A! }- r4 \  j1 K0 r5 T$ |, w, U
  25.     })8 d' u. D# O0 b7 k, L  S6 N8 l. X" t
  26.   );
    $ s0 {* d9 R: g( v
  27. }
    & O8 o1 m- a* i% |
  28. compileScript();
复制代码
这段代码已经可以运行了,但让我们做一些最后的编辑,使我们的脚本在运行时能提供更多信息。我们将为每一步添加漂亮的控制台日志。

$ T; S9 V0 Q/ a, J以下是最终代码( |  D& U) P7 D0 N9 M
  1. import * as fs from "fs";
    ) `5 l4 \& ~# S% ]" b- t0 I
  2. import process from "process";. Y- r5 W  }" G: u7 z7 Y2 p
  3. import { Cell } from "@ton/core";( C4 R% M! b; f) H6 R3 z
  4. import { compileFunc } from "@ton-community/func-js";" n0 s4 ]+ e9 g! D# x3 t

  5. ! t. r, m! o# y- B, I
  6. async function compileScript() {/ z1 h3 X) ?  R
  7.   console.log(8 U( F9 Q1 V3 c. t, S! y0 t* K
  8.     "================================================================="6 P4 @9 S- f2 A, Z
  9.   );
    * |4 |; Q- \! B- T/ a- G' _, I
  10.   console.log(7 E7 m8 ]6 K8 f% j8 g* y( ^7 Z
  11.     "Compile script is running, let's find some FunC code to compile..."& |$ ~! o' _( E1 L3 P& Q
  12.   );
    + d# m- _  z) n( |9 _; p, P) A

  13. " A3 W& ]. }; o. e, d4 m, r+ l
  14.   const compileResult = await compileFunc({8 J% u& Y* p7 r) k% g; Q% q
  15.     targets: ["./contracts/main.fc"],
    + `  k2 a. a; v" K" q. @# n
  16.     sources: (x) => fs.readFileSync(x).toString("utf8"),
    6 L. x3 v5 G/ |# O8 w/ V
  17.   });
    & X2 x5 H7 I0 {/ A

  18. 4 x* b7 ?/ r, s% h% P
  19.   if (compileResult.status === "error") {
    + ], b) G7 W' H1 j" U# b9 X! ^" `
  20.     console.log(" - OH NO! Compilation Errors! The compiler output was:");
    $ s# E( \, L9 P; t& v! X& _% ]
  21.     console.log(`\n${compileResult.message}`);
    2 [4 D% E4 A$ A
  22.     process.exit(1);
    " `5 j0 u& M& S! [
  23.   }
    ) R. s6 W' d2 m% \+ K

  24. + e& ]0 m6 K" z" f* l) R5 f8 O
  25.   console.log(" - Compilation successful!");
    5 g2 P9 P3 r+ Y' L8 R
  26. 4 s+ c1 S( c2 C- j1 B$ N: J2 I* ~
  27.   const hexArtifact = `build/main.compiled.json`;
    3 {; a- }3 O) W# Z7 Q/ L) r7 ^
  28. 1 J8 b9 l+ `2 z  Y& }' {" b
  29.   fs.writeFileSync(
    ! I# G' o2 A0 g7 P7 g5 E- O
  30.     hexArtifact,
    3 A4 @/ M( k" l
  31.     JSON.stringify({
    5 w1 W( b! ~0 A2 r+ T$ n$ C9 t& C
  32.       hex: Cell.fromBoc(Buffer.from(compileResult.codeBoc, "base64"))[0]
    ) _, u0 H- @1 y) Z
  33.         .toBoc()" e( u4 A0 \. v: O% A
  34.         .toString("hex"),; t, p9 _- t" ~2 M; c- I
  35.     })! s8 g2 x- c& v! s1 V8 C
  36.   );# I1 f* z2 c% J# B3 ?2 J7 H
  37. 4 r& O% x: ]6 Q- o* y
  38.   console.log(" - Compiled code saved to " + hexArtifact);7 v# ]" R# _' p5 R: [
  39. }3 T  A! {& Z" d) c1 v1 E- r
  40. compileScript();
复制代码
这是我们的编译脚本,每次修改代码时都要运行它。稍后,一旦我们有了一些可测试的 FunC 逻辑和部署脚本,我们就可以在任何测试或部署之前自动运行该脚本。
我们的 "卫星装配 "实验室设备越来越齐全!
不过,让我们再运行一次 yarn 编译,看看编译的结果如何。为此,让我们打开 main.compiled.fc 文件。
我们在那里看到了什么:
  1. {"hex":"b5ee9c72410102010012000114ff00f4a413f4bcf2c80b010006d35f03fbffbf07"}
    & ?; `+ B: ?! U  k2 r
复制代码
听起来很疯狂,但这就是我们的合约。在下一课中,我们将编写第一个 FunC 逻辑,并将其与我们刚刚编写的脚本进行编译。
到时见!

& a. N( E( r* @8 w# A( E5 ]* P9 v# V: S; h6 u3 h

, C- E8 [  p) w6 w; ?. Q
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则