本帖最后由 riyad 于 2025-3-14 01:12 编辑 : [# W4 O0 r; {4 G+ r2 T( O& l% K
2 C2 ]: B. j% L! j# L8 b* u5 s在本课中,我们将再创建一个项目--聊天机器人。这将是一个后台项目,因为聊天机器人就是这样工作的。你要编写一些运行在服务器上的脚本。然后使用 API 密钥连接到 Telegram 服务器。当有新消息时,你的脚本可以从 Telegram 服务器获取更新。你可以代表聊天机器人触发新消息。基本上,这就是一个独立的应用程序。 我们拿到了合约,部署了它--这就像是我们 dApp 的后台。然后,我们创建了一个网络接口,这样网络上的任何人都可以访问它并与之互动。然后,我们创建了一个 TWA(Telegram 网络应用程序),将其嵌入到 Telegram 中。我们还想做的一件事是编写一个脚本,用来控制和编程这个对话:提供一个键盘,提出一些问题,然后根据回答触发某些操作。当然,还要与 TON 进行交互,因为我们正在为区块链上的合约构建一个接口。 8 m M6 v. \' Z) R+ C- h9 k
准备开始我们在开始一个新项目时,先创建一个新目录并将其移动到该目录中: - mkdir first_contract_tg_bot
- v( f) c& P7 I0 [% C/ p* t7 ]/ L7 k - cd first_contract_tg_bot
复制代码现在我们设置一个新软件包: 7 I7 a3 F, w. n' A/ a
- yarn init- m1 a. q; Z# s$ O
复制代码 是时候安装几个库了。我们将继续使用 TypeScript,所以首先要安装 typescript for node、types for node 和 swc/core,后者可将 TypeScript 编译成 JavaScript:
]! }' { I/ x5 O! z- yarn add typescript ts-node @types/node @swc/core --dev
( R2 C8 V4 [$ P+ f+ F0 A6 N
复制代码我们需要在这里创建一个新文件,名为 tsconfig.json,内容如下:
- L; {9 o2 V) n' S2 t. n- {
, v' v# W; L3 }) r9 c2 W# p$ ? - "compilerOptions": {/ B, ?8 k [2 L( e& C p$ w
- "target": "es2020",. q0 h; _( G+ ^8 R
- "module": "commonjs",
6 B$ A+ V& D2 y0 j) N - "esModuleInterop": true,. Z* x) O+ Q& C+ [. J/ o! a) K* I$ H
- "forceConsistentCasingInFileNames": true,* Z; l! a) \1 a& [; o' |( w
- "strict": true,8 l+ _/ j; `; |3 X/ B9 v
- "skipLibCheck": true," j1 Z9 S* ^: a! {7 K9 F [
- "resolve]sonModule": true
5 h8 e0 T. q [5 G - },
% x/ c! Q: f3 K0 S - "ts-node": {+ g$ j+ ~' W, n0 U, b& X
- "transpileOnly": true,0 g; h) |4 P; x9 a: I/ F" C' q4 n
- "transpiler": "ts-node/transpilers/swc"( w4 G) c0 m: P# ?( @
- }/ O- P0 k, Z; J }% Z$ q1 ^# f
- }
复制代码这里有 TypeScript 转译器的配置和编译器的标准配置。 这个项目是空的。我们需要安装一个新的 SDK,帮助我们与聊天机器人 API 交互。我建议使用名为 Telegraf 的 SDK: - yarn add telegraf
9 f2 `) O; }* s& M
复制代码) L! W, F* _2 X
机器人编程我们已经安装了 Telegraf。现在,我们要在根目录下创建 src 文件夹,并在该文件夹下创建 index.tx 文件。然后,我们立即在 package.json 中创建一个脚本,并通过命令行运行我们的代码。 - {( I7 L" j# d: N; c4 G; K, Z) r
- "name": "first_contract_tg_bot": {+ l4 C( ~4 b
- "version": "1.0.0",
@% p8 i* l/ v - "main": "index. js",
2 X5 M) w$ L& U+ F2 }1 S% Q - "license": "MIT"
. X& a; ?# S: ~# m! z - "devDependencies": {$ t3 M# h& U" v
- "@swc/core"; "^1.3.42",$ V6 P* i/ f3 e. R
- "@types/node": "^18.15.9",
' H; j' Y7 V' P/ g$ I - "ts-node": "^10.9.1",
4 _" _; M/ I( n* o% |! D M - "typescript": "^5.0.2"% I/ y* | | M6 a$ V* {: d: ^
- },
: o- Q& ?$ g% t* v - "dependencies": {6 C% {' ?1 K- S, Z" O5 g) _
- "telegraf": "^4.12.2"
7 k0 k* o; G# V& k) X- G( D - },
{) ~3 |( i- x$ Q) o6 K! Y | - "scripts": {/ |1 x4 @# y- B- j0 ?0 q+ m7 h
- "start": "ts-node ./src/index.ts"7 }# m; {2 j! W l* |
- }. n" v- Y- J7 }: C
- }
复制代码 脚本将使用 ts-node 来实际运行我们要编程的 index.ts。让我们来看看这里的示例。当然,这不是一个 TypeScript API 示例,但我们准备了一些代码 (https://telegrafjs.org/#/?id=example) 。首先,我们要以 TypeScript 的方式导入 Telegraf:
S: W: A' X k" [, z/ H9 Z2 m- import { Telegraf } from "telegraf";# _0 P6 F8 T2 a, K5 e
复制代码接下来,我们需要启动一个机器人实例。因此,我们要创建一个 Telegraf 实例:
( ?' F. T& v9 [. k( x: {3 [- const bot = new Telegraf(' ');" ^; m2 S: D& P
复制代码 它首先接受的是令牌。我们在使用 BotFather API 时已经看到过这个令牌。因此,我们需要返回,看看我们的令牌是什么并将其复制7 s# L( i4 ?, n a s
- const bot = new Telegraf("6015353320:AAF4LZh2hvZSRHQcZNDMyuePl41yd2ZAMyM");3 I* [# T4 ~# Y! T# A
复制代码 开发聊天机器人时,应该保留两个实例,一个用于测试,一个用于生产。因此,我们要用 env 变量将这些令牌分开。在 src 文件夹中,我们创建一个名为 .env 的新文件,以确保该文件从未提交到仓库中。我们将其命名为 TG_BOT_TOKEN,并以此启动 .env 文件:- TG_BOT_TOKEN=6015353320:AAF4LZh2hvZSRHQcZNDMyuePl41yd2ZAMyM
$ F6 m5 j9 v/ M. U
复制代码帮助我们与这些变量交互的库叫做 dotenv,让我们添加它:
/ g. ~# s2 z4 N! y& v- yarn add dotenv
J6 h2 }2 \/ ?' s, F, u
复制代码安装后,我们可以从 index.ts 中访问它: ' K: x8 }9 ^+ F6 H+ v6 O( {7 g3 ~
- const bot = new Telegraf(process.env.TG_BOT_TOKEN!);5 L/ x6 A* W( Y
复制代码但首先我们需要配置并导入 dotenv。因此,让我们在文件的开头进行配置:
+ `' d$ ^. [! V- I' e% G+ h( t- import dotenv from "dotenv"
: K# d' a! t$ y' e% L9 P
复制代码重要的是尽快在项目中运行 dotenv.config 函数,因此我们在导入后添加
* G' g# a% M* Y5 T( y3 l6 J- C- dotenv.config();6 M( {, ?% P' J3 {0 ]- a
复制代码这个变量可能是未定义的,但我们知道它实际上是在 .env 中定义的。因此,我们可以说它肯定会存在。如果它不存在,就会失败,因此不会启动 Telegraf 实例。 酷,让我们看看一步步开始机器人交互后的示例代码是怎样的: - bot.start((ctx) =>, d4 X6 R: g5 B. z2 ?- _
- ctx. reply ("Welcome to our counter app!", {
9 d' a# K( @5 n- U9 A. U1 ? - reply_markup: {( T, o& y" ^" Q h- r$ \) B* A, D$ |
- keyboard: [
' S! W: L- g7 M6 U& d- O, x7 g - ["Increment by 5"],2 G4 }3 Q% x1 k) [% A9 y% G/ X# X
- ["Deposit 1 TON"],% ~# O+ A# K: h% V |
- ["Withdraw 0.7 TON"],
) Y7 E; T% }; C! x- j - ],+ c1 }. w: @4 ^ }2 Q7 E2 o
- },
# ]( M/ w6 @5 t5 w% u1 x' O3 s! ? - })
2 D( n$ U; s! o; ^/ P+ ~ - );
复制代码这个 Telegraf 机器人实例为我们提供了一个启动方法。当你第一次进入聊天机器人时,它就会被触发:你应该记得,当我们刚刚打开聊天机器人时,我们点击了 start。一旦你运行了第一条信息,你就会回复一条欢迎信息,并附加一个键盘。 我们来看看这个键盘会是什么样子。Telegram 聊天机器人可以让你创建自己的键盘,取代你输入信息时看到的原始键盘。你还可以在消息下方创建内嵌键盘。我们稍后再谈;现在我们只使用一个简单的键盘。 在这里,我们将创建三行和三个按钮。在网络上,"请求 "交易(如 "请求存款")是合适的,因为您授权应用程序向您提出请求。但在这里,我们有直接的交易链接,您与聊天机器人本身没有会话,所以按钮中的动作动词更合适,比如 "存款"。当然,您也可以在后台保留会话,但这样做不妥,因为会造成安全漏洞。 - bot.hears("Increment by 5", (ctx) => {
6 Y* [. U' B+ k) g- F - // TODO: send increment transaction
( T+ R7 t, G) A4 P - ctx ,reply("Incremented by 5");
+ p. C9 P5 f; [ - });
" |" j' ]* ~* f1 K1 ^ - bot.hears("Deposit 1 TON", (ctx) => {/ S% A4 n& n2 n2 ^4 a
- // TODO: send deposit transaction* I6 n, `( R7 {! F
- ctx ,reply("Deposited 1 TON");
- l" `; {5 B7 }$ Z) P+ D7 w - });
/ L9 v! l1 \& N! Q - . S0 L/ n3 T+ T0 W2 D9 a
- bot.hears ("Withdraw 0.7 TON", (ctx) =>
1 v9 X4 e I# K! C6 {0 r1 r- K - // TODO: send withdraw transaction
; v" J3 L8 S d9 T+ o1 s- f; } - ctx ,reply("Withdrawn 0.7 TON");
" n% D- s' K6 R! ~7 | - });
复制代码在这里,我们有几个功能。bot.hears 表示机器人会收到这样的信息。我们可以发送回复 "增加 5"。然后,我们还可以添加类似的回复。 最后,我们添加一个函数来启动机器人,并添加几行代码来确保机器人正确退出: - bot.launch();
2 e( Y9 y7 F3 y, z1 }9 Q. Z+ V$ x - # w8 P% q! S* l! S
- // Enable graceful stop
2 z8 `) \% r4 T: I1 q - process.once("SIGINT", () => bot.stop("SIGINT"));' F- R& j1 L B' _8 y
- process.once("SIGTERM", () => bot.stop ("SIGTERM"));
复制代码好了,我们都准备好了,开始吧: ' m, F& ]6 o6 W. G, j( Z: S
- yarn start
2 m+ E. _# ?1 d3 f! _8 b4 a
复制代码我们的机器人已经开始工作,但重要的是要在应用程序中进行检查。打开机器人,再次点击 "开始":
( H( `5 W$ v, V5 b# ]8 F5 z 4 a5 s+ u- j# J! Z2 `: d6 v
正如您所看到的,我们有三个带有文本的按钮。点击其中任何一个按钮后,我们就会得到想要的回复。如果点击 "计数器",我们的应用程序将以网络应用程序的形式打开。那么,我们该如何让菜单操作发挥作用呢?
5 T# M* _/ q( ]8 _- d使菜单操作有效$ V. p' V E- E* |* y
我们正在创建一个部署脚本。大家还记得吧,我们创建了一个链接,可以扫描二维码直接进入钱包,在钱包中签署交易来部署合约。现在我们也可以做同样的事情。一旦你的用户获得了选项,比如以 5 为单位递增,你就可以创建一个链接,让他直接进入 Tonhub 进行支付。
2 W1 w3 {( k T+ i9 Q8 x( \首先,让我们安装使用 TON 所需的库:
) c8 M% W0 f ^5 D# B: c T- yarn add ton-core ton-crypto+ }/ e9 d! I. z& e: z, O: Y
复制代码我们需要 ton-core 和 ton-crypto 来编写信息。要建立链接,我们需要这些库: - ^* Y( |4 O4 d1 @% [4 y! l
- yarn add qs @types/qs --dev
9 G& B X! ]1 T$ B1 \
复制代码现在,我们将重复使用第一课中的一些代码。确保我们的合约地址是正确的。你还记得,在 first_contract_front_end 项目中,我们创建了一个挂钩,该挂钩附加到某个合约。让我们从 useMainContract.ts 中获取地址: . D$ [4 X, V& v8 k: s
- const mainContract = useAsyncInitialize(async () => {; I( Y3 U" _' [5 g* X& B5 Z+ h
- 1 Y8 |6 Q8 N9 M; m* ^# S2 W9 D" S
- if (!client) return;
% P% l. T- u0 b# Z/ i
4 v' n* ~" D5 A7 m% O5 N6 ?- const contract = new MainContract(
3 E3 a; I+ V& e
0 E S, H; b0 v9 Y- Address.parse("EQBDUxTxWo41aCY1SGZJJlDnu4uKvZtbOjuGF9mtf22M1UBq") // replace with your address from tutorial 2 step 8
* a6 D8 O( W V& p - 1 Z. Q5 E# N* `3 g
- );9 V( y& e4 J( n3 M6 A6 o6 j
0 v9 P+ V8 o' {' D% n- return client.open(contract) as OpenedContract<MainContract>;3 X: D: g D8 A: d: p* _" S
# F) @! Y* s. b; e0 a6 `" e- }, [client]);
复制代码现在,我们需要导入地址结构。 " x: R& _' L; h6 p6 `1 S& |+ O
- bot. hears ("Increment by 5", (ctx) => {
. l# H0 u* U5 ^) ^1 u - let link =8 {, `* w5 n% f! z( f
- `https://test.tonhub.com/transfer/` +
2 M0 ^5 Q: l* @: U2 q7 x( X+ o - Address.parse ("EQBDUxTxWo41aCY1SGZJJlDnu4uKvZtbOjuGF9mtf22M1UBq").toString
: G9 M7 I1 \7 a2 x: _$ d - RestOnly: true,
复制代码我们不会在主网中做任何事情,这只是测试网。我们从特定地址中解析出地址类,然后将其转换为字符串。实际上,我们可以直接这样做,因为我们显然需要一个字符串。然后,让我们重新组合,使代码更简洁: ' O/ G4 E$ s6 A" a
- bot. hears ("Increment by 5", (ctx) => {
9 x( h( G, n6 f9 U* m - let link = `https://test.tonhub.com/transfer/EQBDUxTxWo41aCY1SGZJJlDnu4uKvZtbOjuGF9mtf22M1UBq?${qs.stringify(% u5 o5 j' V% K/ S7 M7 r: f
- {
1 Y% e1 m+ ]8 v3 t0 a - text: "Simple test transaction",
1 V- f* `' k9 r7 n - amount: toNano ("0.05") . toString (10) ,; R, y+ d0 H: E: p
- bin: msg body toBoc({ idx: false }). toString ("base64"),
% Z& T% U* C0 p b) l, }3 R - }+ k+ W5 v/ M' ?* ?1 g! j
- )}`;
复制代码我们甚至可以这样做: 9 P9 X) r+ @8 x$ t8 S) o
- const SC_ADDRESS = "EQBDUxTxWo41aCY1SGZJJ1Dnu4uKvZtb0juGF9mtf22M1UBq";
& H3 S5 u8 v9 C7 |3 d& J
复制代码因此,我们把智能合约地址放到链接中: / [& K f1 T& |! d
- bot.hears ("Increment by 5", (ctx) => {% i( y+ W0 b* R2 _0 D
- let link = `https://test.tonhub.com/transfer/${SC_ADDRESS}?$ {qs.stringify(/ l5 ~; i: H& A" U4 h
- {( a# l+ u. L: o, l8 g5 z
- text: "Simple test transaction",
7 B6 V- ~+ F; ~1 K5 B' c! q) w) W - amount: toNano ("0.05") . toString (10) ,
! i# ? A2 a# J- Y0 v - bin: msg ,body ,toBoc({ idx: false }). toString ("base64"),9 x' V' `$ M7 ^4 ~
- }
& |; R2 p: \+ X6 Z; {: m$ D) M- N - )}`;
复制代码 你甚至可以再做一项改进。就像我们为令牌设置环境变量一样,我们也可以在 .env 中设置智能合约地址来执行此操作,因为在生产过程中,你很可能也会在主网上设置一个合约:
3 E3 ~0 F! s# g2 {& D( Z# E0 a- SC_ADDRESS=EQBDUxTxWo41aCY1SGZJJ1Dnu4uKvZtb0juGF9mtf22M1UBq: b9 I3 j+ E0 U+ A+ H
复制代码现在在 index.ts 中,我们不再需要地址对象了。 , Q. ~) T- g# D G* G" n; ?
- import { Address } from "ton-core";' Z- w3 M; t5 N% O; Q; x9 X
复制代码在 bot.hears 的 Amount 中,我们从上下文菜单中选择 Add import from "ton-core" ,并在链接中添加 process.env:
7 C/ @' | Z+ Z: j7 L6 o- bot.hears ("Increment by 5", (ctx) => {
9 u; f' p2 S9 ]; b/ E3 L* |1 K - let link = `https://test.tonhub.com/transfer/${process.env.SC_ADDRESS}?$ {qs.stringify(1 B# t9 s) t) u1 T5 ^1 G
- {
% \/ W+ J- W" s" x - text: "Simple test transaction",
9 z; O, z9 l& h) J$ o. b7 z: _0 X - amount: toNano("0.05").toString(10),
7 N; t. H( p4 X) u. c - bin: msg_body.toBoc(( idx: false )). toString("base64"),
0 z* s! _' U' L6 B - }9 W3 w. y) s" c" _
- )}`;
复制代码在这里,我们需要形成一个信息正文。什么是信息正文?我们使用 "生成器",因为我们要把消息正文作为Cell,然后由 TON 将其转换为字符串表示法。我们要在消息正文中输入什么内容呢? 我们正在创建合约及其封装。我们将发送一个增量函数。为此,我们可以直接从 wrappers > MainContract.ts: - const msg ,body = beginCell()% n4 }5 x8 X# ~0 v
- .storeUint(1, 32) // OP code( T1 u0 b& u. a' r% U- f
- .storeUint(increment_by, 32) // increment_by value+ w# b1 b" {; m2 _# [% g' ~4 p
- .endCell();
复制代码它显示了我们要递增的整数和递增多少的整数。所有这些我都会复制到我的机器人项目中: 9 F, i7 g3 n1 M3 z
- bot.hears("Increment by 5", (ctx) => {
6 U7 A& I: F8 n! Z - $ x6 h; L' O4 M, @7 _
- const msg_body = beginCell()
6 }" | M y3 Q! |: M- @ - .storeUint(1, 32)
0 i9 y4 M, a7 s3 y* w' o! e& o - .storeUint(5, 32)
6 z) J7 A- { \ - .endCell();! g$ r8 w9 R! n, E
0 m: x$ x! n+ p! Y- let link = `https://app.tonkeeper.com/transfer/${process.env.SC_ADDRESS% K7 u, x$ k& H; S8 X
- }?${qs.stringify(+ u i1 V* ~7 b8 d" h7 D& y
- {. E/ e2 Q! l7 P7 s3 m
- text: "Simple test transaction",
" l* ?# q6 B0 X6 E$ H: Y5 U/ d - amount: toNano("0.05").toString(10),
& y2 ?" e8 r2 u. o8 d3 f# m: m; b - bin: msg ,body.toBoc({ idx: false }).toString("base64"),
, d$ Z) R# v4 q5 n - }' d4 J, E! E: l; s- A+ X- [
- )}`;
复制代码 我们不要求增量,但我们知道它是 5,所以我们把 5 放在这里。你可以随意调整,要求增量。在我们的例子中,我们已经有了5个硬编码了。现在我们在开始时导入 qs:+ Y+ g3 m. k, _4 B
- import qs from "qs";; m3 b0 T% I# G: q% k, n
复制代码很好,我们导入了所有内容,现在来对对象进行字符串化。我们说要将计数器递增 5 - 这只是附加到消息中的一个文本。然后把 0.05 作为实际支付交易费用的金额。然后我们使用这个参数费。 在此,我们前往 Tonhub 开发人员文档。我们使用的链接仅适用于 Tonhub,但你也可以使用 Tonkeeper 链接。在文档中,你也可以找出 URL 的结构来提供一些值。 Bin parameter everywhere 用于传递 msg_body,一旦您想发送带有特定参数的消息。这正是我们在这里要做的事情:我们为 Tonhub 创建了一个付款链接。 但在此之前,我们需要让机器人回复用户。一位用户使用我们在开始时提供的键盘给我们发送了 "递增 5 "的消息。我们需要回复,让用户知道他能做什么。我们需要提供一个链接。我们可以简单地发送链接,但我们希望它对用户非常友好。这就是为什么我们要回复一条信息: - ctx.reply("To increment counter by 5, please sign a transaction:", {1 D: u8 g* v/ h. m, \# `* J
- reply_markup: {
, o' i9 d ]! a: T, s - inline_keyboard: [9 s4 c! |: \# u g$ Y4 }
- [{; \+ s$ y5 @5 F( h8 x: i; E
- text: "Sign transaction",$ N3 e! N! |# t# g3 o. k3 N" j0 K" |4 H
- url: link,3 k( b! Y9 G {) _( C
- }]6 _! H; F6 v. m5 j0 x9 `
- ]0 ?: ?, }8 l" y8 k( D
- } W! I: x. C! v- \) S2 b- ?
- })
复制代码然后,我们创建一个额外的参数。回复标记可以是 InlineKeyboard, ReplyKeyboard, ReplyKeyboardRemove 或 ForceReply。这里有多个选项,我们希望使用 inline_keyboard。 上次我们使用的是普通键盘,位于输入行下的同一位置。现在我们创建了一个内联键盘,如上图所示。它有几个参数:文本、签名交易和 URL。因此,我们在 bot.hears 中提供了一个带有链接的 URL 参数。 有一件事我之前没有提到,但你应该记住:如果我们想把某个Cell作为链接发送,比方说,连同一些字符串或链接一起发送,我们需要把它打包成 base64,就像信息正文的Cell一样。 好吧,看来这个办法行得通: - yarn start
6 ^, |, p+ C. R* \
复制代码一切正常,于是我回到手机上。我打开开始命令提供的键盘,点击 "递增 5": + b- R& y* u; H8 U( k
/ F% D# X* D) X( O' s+ g
如您所见,我们收到了一条信息,要求我们签署一项交易,以 5 为增量。交易已发送。如何检查交易是否真的影响了我们的合约状态?如果检查网络应用程序,可以看到 "计数器值 "等于 15,而之前是 10。
1 J3 ~& k- y1 d" u" W' p# q( P& Y' V7 f
进一步改进机器人我们可以通过聊天机器人构建特定的用户流,用户将在后端与我们的区块链进行交互。我们在后端没有任何用户凭证,所以我们实际上是在为他提供钱包链接,让他进行支付。我希望这不会让你感到困惑,因为作为开发者,你应该始终考虑可用性。而这正是可以显著提高可用性的方法之一。 Telegram 中的网络应用程序可让您使用自动消息创建有趣、酷炫的聊天对话。这样,您就能为用户创建极具价值的精彩项目。让我们构建一个类似的链接: - bot.hears("Deposit 1 TON", (ctx) => {- S+ h/ u. T$ v# G# W6 Q: Z
- const msg_body = beginCell().storeUint(2, 32).endCell();
复制代码我们将用 2 来表示存款数额。我们不需要其他任何东西,让我们在 wrappers > MainContract.ts 中再次确认这一点:
; h! h2 p% t0 u- async sendDeposit(provider: ContractProvider, sender: Sender, value: bigint) {) g2 ]' h" U, F% y2 {* x; k" H e
- const msg_body = beginCell()- n2 A/ i. z @4 A7 G
- .storeUint(2, 32) // OP code
+ M( Q0 R2 K6 V8 P5 h - .endCell()
复制代码接下来,我们需要输入存款命令,否则我们将无法在合约上收钱。在 index.ts 中,我们只需输入一个等于 2 的整数(32 位)。在这里,我们说它将是 "Deposit 1 TON"(存款 1 Ton),实际上我们将要求提供 1 Ton的付款。它不必是一个字符串。 // Final code deposit command - bot.hears("Deposit 1 TON", (ctx) => {
% F+ c j% X! _8 Y0 \ - const msg_body = beginCell().storeUint(2, 32).endCell();, A; C5 t8 Q, Y7 J
3 [3 [4 g* D- |* L3 u-
$ p, r/ c L9 q4 H1 M - let link = `https://app.tonkeeper.com/transfer/${4 ^2 I5 N' V: E- w' O6 E9 M) [
- process.env.SC_ADDRESS; [( d: i# C" W& T! Z7 L
- }?${qs.stringify(
: \* ?* }, t/ y) p- ~2 k - {$ b- j+ F, L1 t% C2 z
- text: "Deposit 1 TON",; x7 v; G/ Y( |, s, U- t+ E5 F3 v- B
- amount: toNano("1").toString(10),9 S3 }; }7 C( Q- v0 P! P; O
- bin: msg_body.toBoc({ idx: false}).toString("base64"),6 B& D* d6 K$ z
- }
, l8 n0 z+ I/ c1 U* o* L& X - )}`;
复制代码 因此,我们要求用户向合约发送 1 Ton,并在信息中注明这是存款。我们在这里输入信息,然后删除回复 "已存入 1 Ton",因为我们不再需要它了:
) N& W3 M( O; @- ctx.reply("To deposit 1 TON please sign a transaction:", {5 p# i N! @9 y* s' m: H) r
- reply_markup: {
1 P0 g) {4 d# ?- y - inline_keyboard: [' n4 U; W. F6 ?$ y
- [8 m: f4 H' @$ @' f
- {
) V4 y5 L! Q8 @/ i: y: a% W - text: "Sign transaction",
4 B* m* a* d! H! Z - url: link,
: h( U# ?! E# @ - }9 R6 A+ c# o7 P. ]* `' n4 Y+ h
- ]& y Z3 p5 x3 ?' D$ z
- ]
; w7 `; F2 ^5 z3 s - }& g% p5 V. |/ @
- });
复制代码所以这很简单。我们形成一个消息正文、一个链接、链接文本,将 1 Ton金额设为存款,将正文放入一个字符串,然后用链接中的键盘回复。我们还需要做的一件事就是将机器人的存款逻辑复制到取款逻辑中: // Final code withdraw command - bot.hears("Withdraw 0.7 TON", (ctx) => {+ F* f @* ?( y4 n3 |( r* L
- const msg_body = beginCell().storeUint(3, 32).endCell();3 e: y$ H- l9 ~) l2 g2 M& H
- * N. q" \! `0 M8 N5 ?
- let link = `https://app.tonkeeper.com/transfer/${5 S- x9 O V$ [7 d" T
- process.env.SC_ADDRESS. Z* A1 K2 A# i1 s# M
- }?${qs.stringify(& ~7 r, y1 o0 {
- {) y) F" x9 |# ~' g7 X7 L
- text: "Deposit 1 TON",% p8 ]. y% o/ w F2 |! o: \
- amount: toNano("1").toString(10),! { y$ ]0 P+ D1 t
- bin: msg_body.toBoc({ idx: false}).toString("base64"),
( N+ m! N9 Y; ]1 _3 o - }! O& X& e$ D. _/ _ p
- )}`;
- D" g+ H4 T2 h) g& { -
/ h5 l% d; \, y4 F0 I3 W - ctx.reply("To deposit 1 TON please sign a transaction:", {
i* F, B; z7 D" l3 k, U2 l - reply_markup: {4 F( I3 S7 j' P' X5 v) m
- inline_keyboard: [
$ C: ~, [. W9 J% B - [
9 U1 u6 r( Z9 Y0 p* Q4 L: ` G2 E5 |) ~ - {
( W+ X- h* g6 _) G8 p - text: "Sign transaction",
4 q: o$ Y4 c# A; Q! a, T - url: link,9 l1 S- l2 R0 M4 v, y M6 s/ E/ G
- }/ }( `, @8 z+ r" `( {% c. `
- ]3 }$ h5 @6 R y: m! Z, R
- ]4 X) @* O" \0 h! e5 m6 @
- }
( r1 \! Q3 f0 ~2 }: K6 F+ R& b - });
复制代码现在我们回到提款的包装。在 index.ts 中,我们需要提供想要提取的金额: : h9 G3 [8 N* ] _
- bot.hears("Withdraw 0.7 TON", (ctx) => {
0 F# e' J1 k. h6 ~' T - const msg_body = beginCell().storeUint(3, 32).storeCoins(toNano(`0.7`))endCell();
复制代码我们添加了关于提取 0.7 TON的文字,接下来我们把足够支付GAS费Ton数放进去,因为我们要在这里拿钱: 0 p$ N9 C- N0 C' p" p2 n9 B9 V
- let link = https://test.tonhub.com/transfer/${2 }3 M, l: k/ o& {" y- j- V$ S
- process.env.SC_ADDRESS
& v. |/ A& a u! n; u: l- F - }?${as.stringify({
- F) H/ E0 L/ ~+ R# \ - text: "Withdraw 0.7 TON",
! L' N- O& L0 e6 U. H# l - amount: toNano('0.05').toString (10),
8 F' l7 \$ E+ \ - bin: msg_body.toBoc({ idx: false }).toString("base64"),
* Q/ D# B" ?+ F6 _3 z | - })}`;
复制代码然后编辑机器人信息: 2 K5 O5 g; W& v& M+ P3 K/ n& I' L- ~
- ctx.reply("To withdraw 0.7 TON please sign a transaction:", {/ O$ g9 S3 l m7 ^
- reply_markup: {3 A! a/ O, S. r Q) w* [) h |
- inline_keyboard: [
8 x5 ^* ]. U5 T$ U$ o; K - [{
4 d; C. ?$ C7 Y# f/ C9 x - text: "Sign transaction",) K! m% e. t* m, r) l! q! O
- url: link,6 \$ h! }% z+ @( T6 N
- }]
$ }$ f. k8 F$ d, W - ]
3 j7 V$ A5 {0 p8 H2 @ - }
$ Z0 l8 c* M! {# @ - });
复制代码我们用 yarn start 重启机器人,回到 Telegram 应用程序。现在,我们不仅可以存款,还可以以同样的方式取款: 现在,我们访问 Telegram 中的网络应用程序文档,阅读更多有关该 SDK 中可用内容的信息 (https://core.telegram.org/bots/webapps) 。这里有 initData 和 initDataUnsafe。当我们想在启动网络应用时发送一些原始数据时,就会用到它们。通过这个版本,我们可以检查用户 Telegram 应用程序中可用的机器人 API 版本。通过这个平台,我们可以检测平台。我们还可以调整配色方案和主题参数--这些选项由 Telegram 文档提供。我们可以检查是否已展开,并设置窗口高度。 1 D$ }( u7 Z: N
我们现在需要的是 sendData(发送数据)--一种向机器人发送数据的方法。调用该命令后,带有数据的服务消息就会发送给支持的机器人,其中包含给定长度的数据。重要的是,运行该命令后,会有一条消息发送到你的 Telegram。基本上,一旦你运行了 sendData 函数,你发送的信息就会由我们刚刚创建的后端机器人处理。你的处理方式会是这样的: - bot.on(message("web_app_data"), (ctx) => ctx.reply("ok"));: ?3 N( x( m' i3 S& V5 R. V% R
复制代码您还需要从 telegraf/filters:
! z6 Q$ j ` z# P+ g- import { message } from "telegraf/filters";
1 F6 s+ M& y. C2 {6 ^
复制代码 您可以在这里发送贴纸或消息,但要过滤网络应用程序的数据。在这里,您将收到从网络应用程序发送的数据。需要注意的是,这是用于关闭的,因此一旦运行 sendData 方法,网络应用程序就会关闭。7 ?9 o: e$ W0 r, D. f7 `
4 H# n$ ~( h \: o3 C结论差不多就是这样。我们今天学到了很多东西。实际上,我们已经知道了如何使用一种最好的方式将应用程序推向大众。TON 涉及大规模应用,因此你必须掌握如何构建应用程序,以便将其整合到载体中。如果 Telegram 是这么多人的载体,TON 是我们非常喜爱的区块链,而且这个平台已经为这么多人做好了准备,那么你们为什么不构建自己的应用程序,并将可扩展技术带入已经有这么多用户在等待你们产品的地方呢?
6 l ^$ j5 S* J
我很高兴你们现在已经具备了这样的条件。我希望你已经明白了一切,希望你所学到的一切都能帮助你打造自己的产品。下一章再见。谢谢!
6 m3 v3 k* `% ^ S) F0 T$ V2 R; t \, K! e `4 p) `
6 d! _& {; H9 a3 c
5 m1 {; I: B' ]2 {" g, `' ~) L9 [2 L5 \) x
! l- k8 @. g8 V
) `3 r/ e& H. D7 Q; L5 t- s. i9 s6 J% E4 ?2 S4 Y1 ^9 |& `
1 r' X9 |* k3 o$ i8 s2 a3 V5 I' V2 Z7 g( ?& z1 D
0 E$ W/ U4 P' R& ]( _7 N' e6 l" t; Q& P6 e& r) D) @) a7 q, a
# X* C$ H: g/ K6 x5 N: _. T# s- Z% l. x* K4 g8 o' e
) c2 {! q: _$ R$ ^1 i
9 D0 e9 o$ ]$ e t
- C5 z* {" I: t# Z" C# T: T
3 m: y; j' u) ]9 g! v8 X+ i% j |