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

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

回答

收藏

4.4 存款/提款逻辑测试

开源社区 开源社区 8735 人阅读 | 0 人回复 | 2025-03-08

在本课中,我们将编写一些有趣的测试。
首先,我们要更新之前编写的合约的初始化过程,因为我们引入了一个新变量,它应该存储在 c4 存储器中。
如果您现在尝试运行我们的测试 - yarn test 您可以看到测试将失败。您还将看到发生在我们合约上的交易跟踪,其中一个交易的错误代码为 9. Have a look at the exit codes documentation.
9 - Cell下溢。从片断基元读取数据时,试图读取的位或引用数超过总数。
更新我们的合约包装器
首先,让我们更新我们的合约包装器,以便它能意识到 c4 存储中的第三个参数。也就是说,我们将更新 MainContractConfig 和 mainContractConfigToCell 函数
  1. // ...library imports
    * T; h: ]7 M) ^( k
  2. ! f' S, d6 L' j: y/ d
  3. export type MainContractConfig = {) ^* ~/ ^; A. z# ~
  4.   number: number;
    # r, W2 T7 j# H5 p
  5.   address: Address;
    8 p8 P( C5 ]% r1 M: t
  6.   owner_address: Address;
    % Z/ ~  |7 W4 U& e
  7. };
    % b& T$ A+ R. J& s. c- M

  8. % m- k# Q. z- u' N6 s# Y
  9. export function mainContractConfigToCell(config: MainContractConfig): Cell {
    . [" J( R* |" p: R" q6 A3 ]) I6 T
  10.   return beginCell()4 c  P9 m  v% `, C( z7 }# F9 H
  11.     .storeUint(config.number, 32)& u* Y& u& i$ m3 n3 x  B: y
  12.     .storeAddress(config.address)
    $ [0 E8 W3 q0 A. s) g, _2 n
  13.     .storeAddress(config.owner_address)  u' i1 b1 x, z8 q
  14.     .endCell();- o: \6 V' ~; H0 E$ l5 I
  15. }
    ' c- v: G. w& z2 K7 E
  16. 5 v/ ?$ h8 J8 d+ ~& g+ h
  17. // ...contact wrapper class
复制代码
封装文件中还有一点需要更新-getData 方法,这样它也会返回 owner_address 我们还将创建新方法 getBalance,以测试存款后余额是否增加:
% s. i2 A* s' r4 [3 B# N6 g
  1. async getData(provider: ContractProvider) {
      s, e+ ?8 n; N. F4 s) Y, U* b
  2.     const { stack } = await provider.get("get_contract_storage_data", []);1 _& W! `4 `  x& g1 Y0 i+ y+ Y
  3.     return {) d7 X6 O9 M6 L; m
  4.       number: stack.readNumber(),
    . F' M) z4 L* K. {- |
  5.       recent_sender: stack.readAddress(),
    : U; ]0 \' s; f/ S3 a; ^
  6.       owner_address: stack.readAddress(),6 Q0 U2 h/ ?" \6 q
  7.     };) O6 A! W# Z' I* A- `8 G
  8.   }) H0 H! h( r* K3 o) n: N2 U% S2 z
  9.   
    6 J' \9 T$ A8 N! |& T
  10. async getBalance(provider: ContractProvider) {7 Y, @$ l) ~, {+ S+ j, }, M
  11.     const { stack } = await provider.get("balance", []);
    ) s9 s2 e! \0 A/ R1 e' O
  12.     return {
    . E0 D- L. m% c4 b0 ~6 W' d) o
  13.       number: stack.readNumber(),. |# G' R9 P9 t+ Q% v5 g
  14.     };
    7 t" T" i4 u; e; g/ I4 k
  15. }
复制代码
  1. // ...library imports7 v2 H9 @& n4 e' ]8 G

  2. ; W- P3 u1 X, E5 q
  3. describe("main.fc contract tests", () => {
    . z* q8 i  h5 P3 G/ U, }: l
  4.   it("should get the proper most recent sender address", async () => {
    6 W/ E# E( r6 M5 [
  5.     const blockchain = await Blockchain.create();2 q" ^6 u7 J  G1 r
  6.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];
    4 M) q+ f) j  U

  7. * B1 p: j& l& `: \% s
  8.     const initAddress = await blockchain.treasury("initAddress");2 p+ o0 c$ F1 @' P" Y" C
  9.     const ownerAddress = await blockchain.treasury("ownerAddress");5 L! P; \" |$ s
  10.    
    3 w# }3 ~( t5 i1 R+ }
  11.     const myContract = blockchain.openContract(
    : y) Q7 g8 U/ L; _# P7 X- B% f
  12.       await MainContract.createFromConfig(8 l" R8 K: w7 I' k+ T6 H4 X+ {
  13.         {
    8 |$ c" O' h' O8 O! @
  14.           number: 0,
    # I2 y5 f, Y4 x+ g! w
  15.           address: initAddress.address," t, G2 m9 {5 A( e0 ^
  16.           owner_address: ownerAddress.address, // now we create myContract from 3 parameters6 V7 I  B1 @7 p! q, c. N% Z
  17.         },
    - D( w+ v7 {8 x# M$ k
  18.         codeCell" \4 f( G0 u  {' O# L
  19.       )
    + C# H* o: e7 e2 z# ?$ m$ k
  20.     );" \( q- P7 Q% T/ j4 j" y3 @
  21. 7 F4 {: I1 W6 w
  22. // ...rest of testing code
复制代码

9 ~7 w8 W0 F! K4 N8 [3 w
我们引入一个新的金库,它实际上将是合约的所有者,只有这个所有者以后才能提取资金。这些更新在 tests/main.spec.ts 中进行:
  1. // ...library imports
    $ L4 |9 l* s& a1 @- M* U! D
  2. & A' _" [) b% J9 D
  3. describe("main.fc contract tests", () => {" s' I6 t. g5 T0 t
  4.   it("should get the proper most recent sender address", async () => {
    & _3 p, a* i8 W% ^2 ^9 n3 j9 ^
  5.     const blockchain = await Blockchain.create();& @; U8 G5 u. i1 \# n+ X, x
  6.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];! d4 E; T) E; O% s
  7. 4 X: g& Z( i& S2 g+ m4 G
  8.     const initAddress = await blockchain.treasury("initAddress");
    ) G  o9 V: N" i; j
  9.     const ownerAddress = await blockchain.treasury("ownerAddress");" \& i" {+ i0 [- ]$ v1 n1 Z4 K
  10.     $ R# d! Q1 w4 r- S: X! `/ ]
  11.     const myContract = blockchain.openContract(& c9 O" N) a2 c2 h/ d% q' Y. e/ P  ~
  12.       await MainContract.createFromConfig(9 I( D1 N8 A5 M9 o# H2 p: F& i
  13.         {
    & W9 @$ ^" J5 B( Q% K  u  |
  14.           number: 0,' n4 H  U' h0 R- b- _+ B
  15.           address: initAddress.address,
    8 W: v$ L0 D- }! x5 [
  16.           owner_address: ownerAddress.address, // now we create myContract from 3 parameters4 C9 h5 x$ i. n: h# p  i# n& s5 [: p
  17.         },+ e- @9 h- Z0 F! E
  18.         codeCell
    ! x1 F- E; e7 C, ~6 `' g9 O* p
  19.       )4 k+ O, }  N2 ^
  20.     );! }* Z8 l4 ^- N8 y: a; T" f

  21. 5 Y9 ]! ~7 [+ D  M& s( x1 e
  22. // ...rest of testing code
复制代码
现在我们好了。 yarn test 成功通过我们之前编写的测试。

1 ]( G/ l5 Y" E* ?/ n' C存款测试
让我们在 main.spec.ts 文件中再添加几个测试。
由于我们必须在每次新测试前重新启动合约,因此我们还将把合约启动引入 Jest 的 beforeEach 函数:
  1. // We need to additionally import SandboxContract and TreasuryContract# n8 @! M& Y1 b- }6 t  S; E7 F
  2. import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";# S0 f( M% N! B& [, U* [+ H; L6 R
  3. // ... other library imports3 U" Y4 q6 e- D2 l: d' t
  4. describe("main.fc contract tests", () => {, H8 g) l5 m/ \* I
  5.   let blockchain: Blockchain;
    9 j1 |% S- F) a( n
  6.   let myContract: SandboxContract<MainContract>;
    : E# D2 L6 P, r6 P
  7.   let initWallet: SandboxContract<TreasuryContract>;% S& [$ P4 h. x" @2 r( X
  8.   let ownerWallet: SandboxContract<TreasuryContract>;
    . D* C- N1 D8 Q& ]6 T' S6 i8 g3 E

  9. 9 |4 X8 V/ s- @& ?
  10.   beforeEach(async () => {
    ' F8 v5 C) k, F
  11.     blockchain = await Blockchain.create();3 O& W4 C6 p- i$ G: G
  12.     initWallet = await blockchain.treasury("initWallet");* o9 h7 X( n8 _* ?% S: h
  13.     ownerWallet = await blockchain.treasury("ownerWallet");1 c) s* W5 X0 [- u3 o8 T) [

  14. 4 T9 k1 V1 B' s, S% |
  15.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];
    ; j) h2 d5 m- @) Y7 {7 |
  16. - w  e5 t4 B! v$ _; O; s7 U
  17.     myContract = blockchain.openContract(- H! _. j& Y1 u* m3 g4 }+ `& V
  18.       await MainContract.createFromConfig(" z& b3 F4 [/ m- S
  19.         {
    " B" B# @0 B' T
  20.           number: 0,3 h7 C" ~: H3 K3 c; B
  21.           address: initWallet.address,
    . z$ E4 g, R9 c* v- T1 I
  22.           owner_address: ownerWallet.address,( H3 G) W4 R* v3 G& O6 L" U
  23.         },. `# s3 w( \2 `8 ]
  24.         codeCell+ L- n+ c) q% n: z; X+ E
  25.       )* n3 C' ^" a+ ?
  26.     );
    6 C& g0 M: T% x7 X/ l. }
  27.   });
    6 ?- z4 Z% ^) P& c5 ~3 f
  28. 2 _8 F  |: A( m9 c* Z3 D& M
  29.   it("should get the proper most recent sender address", async () => {
    0 K: [- }( g8 R2 r9 [. c
  30.     const senderWallet = await blockchain.treasury("sender");
    7 o9 G$ R# H. u% S

  31. 7 k# }9 h; J" _, \; }7 r9 x  v# I
  32.     const sentMessageResult = await myContract.sendIncrement(
    + u" h, T6 F1 H2 }' o2 P/ x
  33.       senderWallet.getSender(),) H+ j/ ]* ]( w: z( p
  34.       toNano("0.05"),9 p6 i8 k- S2 g3 f
  35.       1& k* f! H* \2 d
  36.     );
    2 L4 k; O+ U- M- R
  37. " p: _- L+ P1 G$ o& q; ~; ]
  38.     expect(sentMessageResult.transactions).toHaveTransaction({8 J3 ^: o' ~9 r' L! M1 q) R( _
  39.       from: senderWallet.address,; A5 f6 W6 W: j/ O5 L2 F) b
  40.       to: myContract.address,6 W3 |, ^( z" e$ r2 C1 {
  41.       success: true,
      r. c0 Y6 K+ M$ i* U1 `0 b
  42.     });/ C( m1 L6 ?, ~* {& c; s

  43. ; Q- Q. F0 I9 {/ e* q
  44.     const data = await myContract.getData();
    $ H6 M* l6 D0 X: x0 C  s+ g2 [
  45. 6 @! f0 l3 T7 g$ B7 F' _+ t
  46.     expect(data.recent_sender.toString()).toBe(senderWallet.address.toString());
    % }! }: k- W) Z7 E4 Q7 H. V
  47.     expect(data.number).toEqual(1);
    ' I) e/ ~+ i1 Y9 w# U, K$ ]
  48.   });
    : D8 _$ _2 i8 V2 j  h7 I
  49.   it("successfully deposits funds", () => {
    " c% a( I/ n) Z/ ]( u* @
  50.     // test logic is coming9 j( A& x3 ~# K, d& i& P! ^- p
  51.   });# G7 b* a; C1 R; S
  52.   it("should return deposit funds as no command is sent", () => {
    ! R; q& p2 ?! T) B4 d* y
  53.     // test logic is coming
    ! i6 A. K$ g7 b: E+ O! M; F
  54.   });
    & F2 o( i8 \( w+ m
  55.   it("successfully withdraws funds on behalf of owner", () => {9 s# g" h* h* M
  56.     // test logic is coming
    . o  P0 `' b* K
  57.   });5 n! n4 T7 C6 B" {: Y( e! s4 `
  58.   it("fails to withdraw funds on behalf of non-owner", () => {
    2 H2 w/ X' `, i. n% w
  59.     // test logic is coming
    ) z- q3 g% A. o1 S+ U
  60.   });9 y& e9 G) D$ K
  61.   it("fails to withdraw funds because lack of balance", () => {
    3 L$ t0 C% C! s7 ?: i7 ?% e! O$ t
  62.     // test logic is coming0 p5 e, ]7 q8 G
  63.   });4 e+ k- F5 ~1 l1 E
  64. });
复制代码
我们只是将第一个测试的部分行移动到了 beforeEach 中,其余的行应留在第一个测试中 it
让我们为存款写一个测试。我们将发送一条 op == 2 的信息,然后检查余额。像往常一样,首先创建一个封装方法,我们将其称为 sendDeposit:
  1. async sendDeposit(provider: ContractProvider, sender: Sender, value: bigint) {$ D4 B3 e8 F* k. j
  2.     const msg_body = beginCell()
    . z% ?2 m- d. I) l
  3.       .storeUint(2, 32) // OP code" X  o. ?+ J6 @' L2 Z% Y
  4.       .endCell();4 n; E' o- ~1 Z% K8 Y! V
  5. & d! d) {! s3 s! o
  6.     await provider.internal(sender, {) E* j! h4 p6 m4 U+ G: D7 E, a
  7.       value,
    ! B+ v. E6 ^3 N) R# N' I
  8.       sendMode: SendMode.PAY_GAS_SEPARATELY,3 S7 K1 E) D: L3 `8 |% Y! e0 n
  9.       body: msg_body,
    & u9 [6 Q* u0 a$ z% t( w
  10.     });
    ) |# B7 b, q+ ~! g
  11.   }
复制代码
我们将不详细介绍这种方法,因为它非常简单--我们只需在信息正文中传递一个操作码。
下面是我们如何使用该方法运行存款测试。
  1. it("successfully deposits funds", async () => {
    ' E) `# L" t) N( B
  2.     const senderWallet = await blockchain.treasury("sender");; a6 c' k9 O" Y2 s
  3. ) l( G3 u2 |# G: O5 K: Q4 a. s
  4.     const depositMessageResult = await myContract.sendDeposit(; i% U, E- z3 G) G$ y# v2 R% [
  5.       senderWallet.getSender(),% ?" p# x. u0 z+ W4 H
  6.       toNano("5")# x! J9 {  K8 P
  7.     );
    ; Q: ~: `' ?0 B6 Z

  8. / B. d3 m& Y3 H
  9.     expect(depositMessageResult.transactions).toHaveTransaction({* j( ]# D* ]9 @: h1 D
  10.       from: senderWallet.address,. r6 d  g. g6 Y5 [# u9 [/ s# V
  11.       to: myContract.address,
    6 g5 t! j. Z) f; S' |( [
  12.       success: true,
    7 N5 p1 I5 D* o/ K
  13.     });
    ! t! Z+ D. V8 y' V" \

  14. 7 V- Z- Y6 Q2 i8 ~0 Z& F! m
  15.     const balanceRequest = await myContract.getBalance();8 W" x9 ?/ d# M/ J, H7 j' U, I- W& m
  16. 7 {* g' @& ~! d- [
  17.     expect(balanceRequest.number).toBeGreaterThan(toNano("4.99"));1 @5 H- D. L8 M$ y7 b: o/ A
  18.   });
复制代码
请注意我们是如何检查合约余额是否大于 4.99 TON的,因为我们知道手续费会损失一些资金。
我们再写一个存款测试,但这次会出现误报。我们将在没有存款操作码的情况下发送资金,并期待返回交易,因为该操作码未知。
和以往一样,我们还有一个包装器:
  1. async sendNoCodeDeposit($ _: L* X4 y' p
  2.     provider: ContractProvider,! D8 |+ V- E, [8 T2 g) r4 a# v
  3.     sender: Sender,
    " D- W8 h# x# f6 k9 p. a! Q
  4.     value: bigint
    * |5 w, d2 q. K0 @: A- ^
  5.   ) {7 f# L* j  s* K6 m
  6.     const msg_body = beginCell().endCell();# C& J. X$ q; d0 P

  7. 8 D9 [% I; }  h2 G- M' U
  8.     await provider.internal(sender, {
    5 j! E0 m% ?  \- {
  9.       value,1 \* \# h* E1 x1 o+ R5 l6 H
  10.       sendMode: SendMode.PAY_GAS_SEPARATELY,, {6 w( R  |9 e$ o% U( H* ~* \  W
  11.       body: msg_body,
    . e; A3 g- h% u9 ~3 D# N
  12.     });
    ; _) q) ?4 }- o/ S
  13.   }
复制代码
下面是测试代码:

; ^  h: R1 a2 n; e
  1. it("should return funds as no command is sent", async () => {% b0 {7 w8 W5 V5 n6 A
  2.     const senderWallet = await blockchain.treasury("sender");* J1 `7 P; Q0 [- l

  3. ) b9 Y& _: Z, T, e& V! `. }% ^
  4.     const depositMessageResult = await myContract.sendNoCodeDeposit(1 y& G) Y+ a: p
  5.       senderWallet.getSender(),
    ' X# j2 b0 c$ `% n
  6.       toNano("5")) i: o+ B) k4 H7 ~" g
  7.     );
    $ s/ M' i- [3 Z9 ?) r( r7 W* G

  8. % z, x; s7 o) O7 d
  9.     expect(depositMessageResult.transactions).toHaveTransaction({
    1 N2 a" N, K2 H/ A8 n- ^
  10.       from: myContract.address,. r* ]! f7 `  [$ u
  11.       to: senderWallet.address,
    3 g7 O# G! d6 `: x
  12.       success: true,
      B( n4 |2 E$ V' k2 y
  13.     });
    0 ~! q/ I3 P1 s  N- W9 j$ i' N

  14. ( ~' i5 ^. y( _6 h+ [/ L4 B' k
  15.     const balanceRequest = await myContract.getBalance();
    ' X5 g7 G. L( n+ \- i+ T( |! I
  16. 8 W( J& @- p" _5 i! a& l, ^0 r8 I
  17.     expect(balanceRequest.number).toBe(0);
    / i' X) z" h1 t
  18. });
复制代码
提款测试
让我们先创建一个用于提款的新包装器:
  1. async sendWithdrawalRequest(
    ' C$ I* ]  x: D; T
  2.     provider: ContractProvider,* k# c/ x* t2 x  o  A
  3.     sender: Sender,
    - Y+ F5 B: Z+ o7 C# M! T
  4.     value: bigint,
    7 i% W2 J( b) x' N
  5.     amount: bigint/ D+ }$ a5 y. K! c  z. q1 e2 x
  6.   ) {
    6 r* L' J% {9 o( \( M6 r
  7.     const msg_body = beginCell()  z( e) |' |. s. S4 h' h7 i5 T
  8.       .storeUint(3, 32) // OP code2 `. [) V! g' R% p& C3 H% S/ N
  9.       .storeCoins(amount)
    + @$ I: P- D/ c3 Y0 ~
  10.       .endCell();. S) d8 r- J, H* V

  11. - S2 k! R% ?, W6 a- K0 @
  12.     await provider.internal(sender, {) S. f$ W! @$ q" Z/ b$ I
  13.       value,
    ) T& f, o3 O) S3 U, ^2 x
  14.       sendMode: SendMode.PAY_GAS_SEPARATELY,
    3 P: Y: P2 L7 M% v2 ~$ k
  15.       body: msg_body,
    ' w( R8 ^, `8 ^0 K  w/ N0 g1 t
  16.     });
    ! J3 K; O  d- p$ J$ i5 S. T
  17.   }
复制代码
我们输入适当的 msg_body 和所需的提款 amount 。
我们将进行 3 项不同的测试。让我们一起来看看:
  1. it("successfully withdraws funds on behalf of owner", async () => {
    ) J4 k. C2 ^# m! W
  2.     const senderWallet = await blockchain.treasury("sender");6 Y" f, r9 e3 b
  3. % A+ j0 r2 A  k8 `7 [8 i% w, U) T
  4.     await myContract.sendDeposit(senderWallet.getSender(), toNano("5"));
    2 u& J- U; [* ?4 p1 G
  5. 7 ]9 F6 [! r, b) O- O
  6.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(! ?5 U! x" m, c( ~
  7.       ownerWallet.getSender(),$ L" Z1 `) B7 m. i
  8.       toNano("0.05")," t' K4 ]7 z# P9 w9 ~% M4 o+ z
  9.       toNano("1")
      {. w8 z1 Y9 Q& ?4 `
  10.     );3 J6 Y6 R0 f! J! o# h* C3 O6 t' ^
  11. 8 }1 X& p4 O; ]5 g
  12.     expect(withdrawalRequestResult.transactions).toHaveTransaction({
    6 X: ?" d& v' |) |
  13.       from: myContract.address,6 n* Z0 e3 [9 k& B
  14.       to: ownerWallet.address,- }0 c) S- C1 s! u! o
  15.       success: true,' u: M3 k- @- i
  16.       value: toNano(1),, s9 T- u3 l" D) O5 N
  17.     });
    / A! ~( R! i$ T+ N
  18.   });
复制代码
要成功提款,我们首先要正确存款。然后我们调用 sendWithdrawalRequest 指定我们要提取 1 Ton。请注意,0.05 Ton只是为了支付费用而指定的信息值。2 c! b/ H) u$ z- V
  1. it("fails to withdraw funds on behalf of not-owner", async () => {
    " f, |5 B" n  U3 [$ ^  }
  2.     const senderWallet = await blockchain.treasury("sender");/ ?/ G. O( g9 S' \) f2 D
  3. 4 [8 j  E- Y, o9 z& Z
  4.     await myContract.sendDeposit(senderWallet.getSender(), toNano("5"));
    : a  J9 I" e6 z- P
  5. ; E( k- m/ q8 U5 }& P
  6.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(
      c0 f" E/ \- x
  7.       senderWallet.getSender(),
    * ?8 u7 [7 X! |. u% \2 h; l, q
  8.       toNano("0.5"),3 m, n; t: F* I# M2 `' M
  9.       toNano("1")7 B( V) c4 X/ B3 q9 ]
  10.     );
    7 f. r$ [8 k& f; d

  11. 6 t$ ^% P$ q% }5 Z- U
  12.     expect(withdrawalRequestResult.transactions).toHaveTransaction({% F/ J4 R9 Z4 l8 r" z* L
  13.       from: senderWallet.address,2 @* P* \' w4 |; ]  |4 ]5 }$ z  t
  14.       to: myContract.address,3 C. c( q: r# \& I6 m% w+ d+ Z5 ~
  15.       success: false,
    " G) d, d4 X6 k; x+ o8 D5 v
  16.       exitCode: 103,! f2 L- g, ~5 J* H& {8 ?
  17.     });
    4 O8 q% I% P3 p1 m! r3 q7 P/ `
  18.   });
复制代码
在本次测试中,我们代表发送方钱包而不是所有者钱包发送提款请求(两者的区别在于初始化时我们提供的助记词).
还请注意,我们是如何通过 success: false 和具体的失败原因 exitCode: 103. 为了确保我们做得正确,请看一下我们的合约代码,我们有这样一行代码:
  1. throw_unless(103, equal_slice_bits(sender_address, owner_address));& T; f1 Q0 u" ~
复制代码
我们进行最后一项测试--由于没有余额,提款失败:
  1. it("fails to withdraw funds because lack of balance", async () => {" K) M1 P, E" ~( }* Y
  2.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(/ x; A; M! ^! g' P& h' O# [; w. n
  3.       ownerWallet.getSender(),+ j3 |% z# {( |8 w" N2 O7 H9 U& s
  4.       toNano("0.5"),: b% }2 U# s. u
  5.       toNano("1")% F, o' S1 F% U5 z0 l) b
  6.     );
    4 P" s0 i& k- ^7 D4 F6 q
  7. 5 ?, C; N( {3 J
  8.     expect(withdrawalRequestResult.transactions).toHaveTransaction({! ~; ^3 R7 t, Q: r. `  u1 c
  9.       from: ownerWallet.address,
    , u6 h0 [( {2 Y5 a- ~/ }6 ?- z
  10.       to: myContract.address,5 R+ F) `4 \$ k0 @& h
  11.       success: false,
    5 K8 c, T0 y. `" y$ k
  12.       exitCode: 104,
    ) V; L5 S- o6 ]/ J, W
  13.     });4 E+ [5 a, L8 X( I* Z7 Z  b. t
  14.   });
复制代码
  1. throw_unless(104, balance >= withdraw_amount);
    1 J; x* m! q9 @& _" t: o/ H, f
复制代码
就是这样
几章之后,我们将学习如何构建网络客户端,以便与合约进行交互。
, G. G4 _8 T' }

5 D7 y7 O% [0 s5 h: G% |
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则