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

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

回答

收藏

4.4 存款/提款逻辑测试

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

在本课中,我们将编写一些有趣的测试。
首先,我们要更新之前编写的合约的初始化过程,因为我们引入了一个新变量,它应该存储在 c4 存储器中。
如果您现在尝试运行我们的测试 - yarn test 您可以看到测试将失败。您还将看到发生在我们合约上的交易跟踪,其中一个交易的错误代码为 9. Have a look at the exit codes documentation.
9 - Cell下溢。从片断基元读取数据时,试图读取的位或引用数超过总数。
更新我们的合约包装器
首先,让我们更新我们的合约包装器,以便它能意识到 c4 存储中的第三个参数。也就是说,我们将更新 MainContractConfig 和 mainContractConfigToCell 函数
  1. // ...library imports3 x1 x% O' _  l% P! a
  2. ' D% K+ m% B/ N6 Z* y* r
  3. export type MainContractConfig = {, L8 m, H# t  h* B
  4.   number: number;9 ?. N. o1 k8 |4 ~% r  }
  5.   address: Address;$ s9 P- c9 ^! ?: g* L
  6.   owner_address: Address;; w( V) ]' ?* N: m/ ]
  7. };2 F, v: J) y8 o$ T( Q2 B& v" A
  8. 3 F: w" ]( Q. c5 z: F
  9. export function mainContractConfigToCell(config: MainContractConfig): Cell {9 y2 J8 N3 }/ R# C
  10.   return beginCell()
    / ~  o: g' j/ r
  11.     .storeUint(config.number, 32)0 }9 R- y: c6 s- f* u
  12.     .storeAddress(config.address)
    1 H8 ]. J2 n! [
  13.     .storeAddress(config.owner_address)
    + d* i& Y% a" ~" s
  14.     .endCell();0 _2 }2 e% `9 e. K8 d" ]) @" c& `
  15. }/ H! ?2 ~& Y- a) X1 ]
  16. + i" L" o& d" e1 X9 ~( i
  17. // ...contact wrapper class
复制代码
封装文件中还有一点需要更新-getData 方法,这样它也会返回 owner_address 我们还将创建新方法 getBalance,以测试存款后余额是否增加:
/ w7 K( S1 @9 V9 n$ F, v
  1. async getData(provider: ContractProvider) {* g0 u' g4 A, r# Y# W7 a4 P: ^
  2.     const { stack } = await provider.get("get_contract_storage_data", []);
    8 N# D0 R* ^) r% N
  3.     return {
    ) s% [+ u" b2 O# x' \
  4.       number: stack.readNumber(),
    5 u8 L+ \; E1 @# ?% e) [, h' Q$ j
  5.       recent_sender: stack.readAddress(),4 ?: L! e, H+ o. }
  6.       owner_address: stack.readAddress(),
    & j% C- t& e8 \
  7.     };. v' @* I4 x' {. {' z8 f
  8.   }0 n/ S5 ^9 m. `4 M5 `: _. s
  9.   
    ( n: y9 h2 Y- F. O9 Z. w4 b2 i1 Y. ]
  10. async getBalance(provider: ContractProvider) {" W$ w( q7 a* m* V4 q% |5 _
  11.     const { stack } = await provider.get("balance", []);
      v9 Q  F; Y' a. n8 R. n' i% h. U
  12.     return {; i0 v& z% }# a4 P; e
  13.       number: stack.readNumber(),
    , e) F, `* L* X
  14.     };8 a& _, I; n. X1 C: }
  15. }
复制代码
  1. // ...library imports
    5 P) \+ |0 _! Z- A1 g: a
  2. ! ?& A' J! t, w1 F
  3. describe("main.fc contract tests", () => {) j% o& R0 c. S2 C6 ]- f7 S5 y
  4.   it("should get the proper most recent sender address", async () => {
    ( g+ x- X% [" X1 V9 C
  5.     const blockchain = await Blockchain.create();
    8 H: j# P% {+ e% J# s+ t& k# Q
  6.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];
    3 k9 Q! L% _( }! t. a: L$ i/ T
  7. 3 h" g' \. c6 u8 o; Q& c' `$ I+ P
  8.     const initAddress = await blockchain.treasury("initAddress");9 x; b: C1 \1 d) v0 u2 Q
  9.     const ownerAddress = await blockchain.treasury("ownerAddress");
    5 N0 T; g; H4 {' C# ^# I3 B
  10.    
    + w  [& O9 u* y- O3 Y3 N  L
  11.     const myContract = blockchain.openContract() b# U5 V  }; O) ~( ~" l
  12.       await MainContract.createFromConfig(
    # P2 W5 a' X4 G2 a. w0 u
  13.         {+ u- R. V- \" n. l; \0 H9 \8 b! r
  14.           number: 0,
    . b( m  l- n  b
  15.           address: initAddress.address,& p9 W/ f2 ^7 H, g
  16.           owner_address: ownerAddress.address, // now we create myContract from 3 parameters) p4 |; S" @4 _; ?6 m, |
  17.         },2 o5 Z+ z5 w' S) p6 h8 u
  18.         codeCell
    $ z2 X4 u; K/ T, @; K  q4 I1 j
  19.       )4 l3 ?1 v  f# Y8 G+ U
  20.     );( X- o) R# N  t& X; |9 x0 Q( G( }
  21. ( n) a0 n2 f! ~1 b. u9 `- g; t' \
  22. // ...rest of testing code
复制代码

! g! x3 I2 |" G, ?+ i
我们引入一个新的金库,它实际上将是合约的所有者,只有这个所有者以后才能提取资金。这些更新在 tests/main.spec.ts 中进行:
  1. // ...library imports* H3 x" ]  `+ _1 C& v8 V. `) x

  2. ; w, ]9 P# h1 W. L( |
  3. describe("main.fc contract tests", () => {9 O. z# b' E2 h- `+ c
  4.   it("should get the proper most recent sender address", async () => {
    2 U8 B5 \+ |1 o- F( n
  5.     const blockchain = await Blockchain.create();
    ; F2 F2 Y1 r9 B( J
  6.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];8 f! C5 m$ Q3 g$ T: P6 Y9 n( n
  7. 3 M# E' R' I! r! C* R" N  d# O
  8.     const initAddress = await blockchain.treasury("initAddress");9 h" f0 E$ ]; B) [% y9 v- e% K- A
  9.     const ownerAddress = await blockchain.treasury("ownerAddress");
    , o4 V- z* n3 s6 R  m. l; V
  10.    
    " f( b9 |. M8 W( V  ~; [
  11.     const myContract = blockchain.openContract(/ r( b: n1 z. ]% g. v8 u
  12.       await MainContract.createFromConfig(" O( c$ l: l  }- T; j( z
  13.         {
    * l. ~% e% V) G! m( H- A; p
  14.           number: 0,
    - i' l( N' ~* {3 A
  15.           address: initAddress.address,8 u0 X9 ]' p& P4 U
  16.           owner_address: ownerAddress.address, // now we create myContract from 3 parameters
    0 h5 r" K/ t3 d+ V( D/ `
  17.         },; ?/ A. l5 N9 a! l
  18.         codeCell
    % B- d4 ~* K: A/ g3 U/ C! M  d
  19.       )
    1 f, _+ r' g- Q' _$ T
  20.     );
    5 d$ g+ F  W8 W' Y% \
  21. ' ]) R1 X: d* E8 l5 h
  22. // ...rest of testing code
复制代码
现在我们好了。 yarn test 成功通过我们之前编写的测试。
* n" X5 c: R( i0 T
存款测试
让我们在 main.spec.ts 文件中再添加几个测试。
由于我们必须在每次新测试前重新启动合约,因此我们还将把合约启动引入 Jest 的 beforeEach 函数:
  1. // We need to additionally import SandboxContract and TreasuryContract7 K% X1 S7 n1 H% v1 m% u4 {( J
  2. import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";2 @, e3 f% ]0 m( s) P, I/ K$ S
  3. // ... other library imports( Y" R' x1 A6 Z5 L
  4. describe("main.fc contract tests", () => {
    ) N% x: E1 W% O- j4 O
  5.   let blockchain: Blockchain;3 x. B3 o4 h$ `2 |: p$ V
  6.   let myContract: SandboxContract<MainContract>;
    : R. r. X. X8 ~6 j
  7.   let initWallet: SandboxContract<TreasuryContract>;
    * X6 t4 p' T' S7 t6 x+ Z6 m$ ]
  8.   let ownerWallet: SandboxContract<TreasuryContract>;
    8 O2 u9 B/ H6 E3 C% i! D4 S
  9. ( S4 x8 m# Z" I0 W) E& G
  10.   beforeEach(async () => {
    6 p: N; O& ]& Y' E' s8 e7 u
  11.     blockchain = await Blockchain.create();
    ' Z6 w2 \3 Z, u- G* c( V4 g1 O
  12.     initWallet = await blockchain.treasury("initWallet");2 w0 G. n/ A" G: v% G6 G  ~
  13.     ownerWallet = await blockchain.treasury("ownerWallet");* r# M5 ^. t" _5 u) h+ M% S

  14. ) k+ x- \& C: N3 D# d' B% @
  15.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];/ R- k5 ?' ^: x  p. f
  16. 0 J0 Q8 }3 N$ X. r. {/ B
  17.     myContract = blockchain.openContract(' p  N# b. l/ Q" o% u# L4 B
  18.       await MainContract.createFromConfig(& s7 v' ^, @1 s3 k
  19.         {" c, s' O6 v  {* U
  20.           number: 0,& n4 F. I/ k0 L. G/ q+ Q% m8 d
  21.           address: initWallet.address,8 J5 I6 E) A1 u( X) k9 o) v% Y
  22.           owner_address: ownerWallet.address,8 y% ]) r( ^$ x' _/ g
  23.         },
    % c5 z. t3 o6 ~/ l2 K
  24.         codeCell. h3 i! ^1 s+ |# u9 N) t
  25.       )
      T$ E* ^- a/ A& c2 x. T" [+ l
  26.     );: u4 X; I! T( c. @
  27.   });6 A, o8 m6 p( Q) F( C

  28. 7 V5 I# _( f4 E2 D4 J" X; d
  29.   it("should get the proper most recent sender address", async () => {
    8 `) v. M! `, E0 S
  30.     const senderWallet = await blockchain.treasury("sender");
      T' u' k! H; z5 g  z' X2 w

  31. $ S6 v1 `" \! ]
  32.     const sentMessageResult = await myContract.sendIncrement(
    3 s$ b5 i+ |6 A8 l1 `
  33.       senderWallet.getSender(),
    ' a" k5 P- b' i! _$ x" P: C
  34.       toNano("0.05"),2 ]) U2 R, r& L9 [
  35.       1
    ! Z9 P" S; J0 X
  36.     );
    2 t" J7 D3 i5 r  O

  37. , h$ k1 V3 r& q2 ]4 q/ m
  38.     expect(sentMessageResult.transactions).toHaveTransaction({1 b* X) }# C# b8 z( `8 s% f! k1 S
  39.       from: senderWallet.address,$ D4 ]! B! n; q
  40.       to: myContract.address,
    4 ]. A9 A+ ]- g3 l; R9 K
  41.       success: true,
    4 f2 k" c- P& J# W% B# S. i
  42.     });% k! x8 l5 u7 R: b: S! f& i! S

  43. 0 f0 V$ T* E, F: J- }/ K0 a9 A% X% ?
  44.     const data = await myContract.getData();. c$ G% u# Y( b7 ^; B
  45. * U0 d/ j+ F* ~6 W% Q1 u
  46.     expect(data.recent_sender.toString()).toBe(senderWallet.address.toString());) J; a& y8 [9 ~7 i
  47.     expect(data.number).toEqual(1);6 C$ U" U3 B/ N9 e  e3 b, i
  48.   });
    6 Y4 a6 Y% |0 _
  49.   it("successfully deposits funds", () => {$ ?& i  `& E' @# a
  50.     // test logic is coming& O& ?- Q, F4 }
  51.   });! r+ d4 l' {) u! G- D) \
  52.   it("should return deposit funds as no command is sent", () => {: S/ J5 @! s5 E2 ]; P: z
  53.     // test logic is coming
    7 C/ z0 g2 y# I* ^, m9 h( U; J* Q
  54.   });
    + o. x) d! W+ n% U, [3 u* M/ i
  55.   it("successfully withdraws funds on behalf of owner", () => {+ }/ v* K) s! Y) z% O+ ^2 N' ^
  56.     // test logic is coming+ Y$ a" x; o/ {5 i6 u1 f) u- k5 A
  57.   });
    8 u" N" l8 z9 w9 e. E& q4 s
  58.   it("fails to withdraw funds on behalf of non-owner", () => {
    ' I$ U+ N7 O# }) l2 T
  59.     // test logic is coming+ H* r: u( c$ y5 c8 u8 T
  60.   });+ f) k3 o# E+ @. h( @
  61.   it("fails to withdraw funds because lack of balance", () => {
    3 }1 V& ~/ j! R3 O% `8 E/ u
  62.     // test logic is coming& O/ ]5 I6 P3 T) K' S
  63.   });
    ' z" y! I- o# e7 V8 k. ]
  64. });
复制代码
我们只是将第一个测试的部分行移动到了 beforeEach 中,其余的行应留在第一个测试中 it
让我们为存款写一个测试。我们将发送一条 op == 2 的信息,然后检查余额。像往常一样,首先创建一个封装方法,我们将其称为 sendDeposit:
  1. async sendDeposit(provider: ContractProvider, sender: Sender, value: bigint) {/ U$ s/ I9 A9 |" G+ e
  2.     const msg_body = beginCell(), E  F, ~1 L+ B* \
  3.       .storeUint(2, 32) // OP code
    , {6 w- a3 b* Z& Z
  4.       .endCell();) i, }1 _9 i# B& n
  5. 7 T; m6 @( h: V8 `; \, \3 I6 ~
  6.     await provider.internal(sender, {: u3 G$ h2 T: O2 A; Z: i1 z
  7.       value,0 x0 j/ l; z) k, f/ ?0 {5 l; I; u
  8.       sendMode: SendMode.PAY_GAS_SEPARATELY,
    / U  k# J& G1 B' b% D5 G& T6 A
  9.       body: msg_body,
    - Z$ o  H8 I& r: V4 \9 o. K: b  N
  10.     });
    3 Z' g% ]1 {# V' @
  11.   }
复制代码
我们将不详细介绍这种方法,因为它非常简单--我们只需在信息正文中传递一个操作码。
下面是我们如何使用该方法运行存款测试。
  1. it("successfully deposits funds", async () => {
    # R9 d. h7 p. f4 O, c3 q0 o
  2.     const senderWallet = await blockchain.treasury("sender");. E# B& W% n, M2 V

  3. 0 q. B1 G! h  k' V4 b
  4.     const depositMessageResult = await myContract.sendDeposit(
    / T6 r% C$ t3 L) t* B8 H
  5.       senderWallet.getSender(),. Z4 o  Z' @7 J" M$ S+ _7 N
  6.       toNano("5")* y7 J4 b. \6 o( M4 J: Y
  7.     );
    * }$ f3 T$ g5 k" V* w

  8. - Q" O7 E% t% W8 G
  9.     expect(depositMessageResult.transactions).toHaveTransaction({
    ( l, k- U* E! B$ i% ~# q8 ]$ B
  10.       from: senderWallet.address,1 c+ q( {  i! Y6 O
  11.       to: myContract.address,
    3 C: j3 e% @; C$ f
  12.       success: true,0 E3 `$ o' [5 o7 `. D' i' Y: i% C
  13.     });& M9 R; L1 ?2 i( c
  14. 8 f. w  a  Q5 V/ O4 _
  15.     const balanceRequest = await myContract.getBalance();  E( c1 N- \5 P# E& d
  16. 4 A# b5 ]" u+ _! s
  17.     expect(balanceRequest.number).toBeGreaterThan(toNano("4.99"));
    6 o4 A3 H2 M  E0 R' D
  18.   });
复制代码
请注意我们是如何检查合约余额是否大于 4.99 TON的,因为我们知道手续费会损失一些资金。
我们再写一个存款测试,但这次会出现误报。我们将在没有存款操作码的情况下发送资金,并期待返回交易,因为该操作码未知。
和以往一样,我们还有一个包装器:
  1. async sendNoCodeDeposit(4 c9 S: q3 P: M: F3 G+ ?
  2.     provider: ContractProvider,1 s0 X$ P% t0 C( E. k) n
  3.     sender: Sender,
    ; l/ U" y) ]0 s
  4.     value: bigint* Y2 a8 B; B7 R5 d9 w
  5.   ) {9 b- g  w% [# M( q  R
  6.     const msg_body = beginCell().endCell();
    7 L7 f! Y0 D% w* c
  7. # O1 X9 L" _3 F( J
  8.     await provider.internal(sender, {( b' F9 o$ c& ~8 N% k
  9.       value,# T- Z8 B3 ~0 c: g
  10.       sendMode: SendMode.PAY_GAS_SEPARATELY,
    / D5 C1 N1 |) V' w9 \, [! N
  11.       body: msg_body,
    3 l) Z2 q% B1 N8 K4 H$ [. r6 v
  12.     });9 C. N0 d( R4 z8 m
  13.   }
复制代码
下面是测试代码:
2 j2 d4 t) i6 _3 w& R3 c' r
  1. it("should return funds as no command is sent", async () => {) h! ]3 r. l. N) l
  2.     const senderWallet = await blockchain.treasury("sender");
    2 W5 C3 p' p2 m' @

  3. * D3 L# W9 q" c( z
  4.     const depositMessageResult = await myContract.sendNoCodeDeposit(+ b* {9 O" Z3 ^, g
  5.       senderWallet.getSender(),
    2 I/ |) g" U# ]+ C1 a* E8 `
  6.       toNano("5")
    0 {/ L! y+ X; A. v! P
  7.     );/ `9 y1 T% p0 f, ]3 Q2 y) f
  8.   B' \3 H: @% O( T
  9.     expect(depositMessageResult.transactions).toHaveTransaction({* [, H" ], S$ R+ d0 e" n% ?! t2 Y
  10.       from: myContract.address,
    - ?6 ?* e1 Q  O, @
  11.       to: senderWallet.address,: x) F+ L$ h% w& f4 V3 ~8 X4 @5 t$ y
  12.       success: true,
    3 T$ p/ @# u1 u, B
  13.     });+ g, D7 M- R7 Q& k' N7 B7 `; A

  14. 5 U( L) |# \4 n: \+ H
  15.     const balanceRequest = await myContract.getBalance();# N' q" J- |) w, }: Z+ L0 [

  16. 0 c/ \) g: D; W& K2 f, A
  17.     expect(balanceRequest.number).toBe(0);! s/ A! f: W5 A3 `  }
  18. });
复制代码
提款测试
让我们先创建一个用于提款的新包装器:
  1. async sendWithdrawalRequest(, y- f0 ^- H: R, M$ Y
  2.     provider: ContractProvider,! x2 Y5 k$ k; r, ^
  3.     sender: Sender,
    ( m3 L* @4 p9 ]* R3 v4 M3 e
  4.     value: bigint,  r, T. a3 X1 U7 A& j% L/ b  N
  5.     amount: bigint# y6 S4 K" G+ T" C. W5 z. O8 ?
  6.   ) {; D* h2 x$ j0 x% t
  7.     const msg_body = beginCell()* E. _/ G5 p7 s. @  d
  8.       .storeUint(3, 32) // OP code
    2 ?" t  I) S1 G/ Z+ A) q
  9.       .storeCoins(amount)
    4 w5 ]1 g0 c* E* Y' j& U
  10.       .endCell();$ L, c# E$ `7 P

  11.   E- d; J6 c6 T) b
  12.     await provider.internal(sender, {
      J9 t9 d; \0 @7 @) Z. \3 I+ d, d
  13.       value,
    1 p2 i5 U& n4 C. k1 X* B
  14.       sendMode: SendMode.PAY_GAS_SEPARATELY,
    : z$ W, `' X' Q$ v+ {$ {/ z- @
  15.       body: msg_body,  J5 `6 \4 ?. Q
  16.     });
    & i2 ]) f" I8 N) h- |/ Q
  17.   }
复制代码
我们输入适当的 msg_body 和所需的提款 amount 。
我们将进行 3 项不同的测试。让我们一起来看看:
  1. it("successfully withdraws funds on behalf of owner", async () => {/ N& L+ Q1 Q, |2 W: A$ m7 u
  2.     const senderWallet = await blockchain.treasury("sender");
    , M8 {) q3 _. y/ |1 q" Z* l( f9 U

  3. 4 c2 a+ g' L2 r4 b3 b, K- c$ J
  4.     await myContract.sendDeposit(senderWallet.getSender(), toNano("5"));. j. |4 _. Z9 h6 y- i" y% }# w

  5. ' F, n! `% r( Z$ {! N7 x
  6.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(
    2 N# Q" |! j% m1 t, F' R9 @
  7.       ownerWallet.getSender(),
    ) R, `% V, _  R6 Y9 b4 A
  8.       toNano("0.05"),
    ! d$ p( l, @: l1 Q+ l: a
  9.       toNano("1")$ d0 Y' ^  d+ E4 g8 W% o
  10.     );! G, n) f! y1 D# h* t7 `

  11. 8 Y) W) e' T- r7 T
  12.     expect(withdrawalRequestResult.transactions).toHaveTransaction({3 B- m  B: V6 X. f4 q
  13.       from: myContract.address,
    2 Z3 y0 f9 z# M( G
  14.       to: ownerWallet.address,% t0 |7 k  K% ~3 n+ p
  15.       success: true,
    : T4 \  b- n; a, D3 J* B6 @
  16.       value: toNano(1),
    ; H: r9 Z/ L0 t3 F8 ~
  17.     });
    ( ~4 R& k# ~$ m, |! l( F
  18.   });
复制代码
要成功提款,我们首先要正确存款。然后我们调用 sendWithdrawalRequest 指定我们要提取 1 Ton。请注意,0.05 Ton只是为了支付费用而指定的信息值。( r* B( R: o7 f, c. s
  1. it("fails to withdraw funds on behalf of not-owner", async () => {9 }( P$ h) @! o  D* z( g2 X' d4 p" E
  2.     const senderWallet = await blockchain.treasury("sender");
    ! {7 L( q: l; A* X5 P
  3. % @7 L* ~. X# t* o8 u  m1 y" ]
  4.     await myContract.sendDeposit(senderWallet.getSender(), toNano("5"));8 s" {4 R0 O1 w# L. Z( q$ ^; _( p

  5. - n* x4 ]& U* I
  6.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(5 V9 H/ q, A. k
  7.       senderWallet.getSender(),  n. [( v5 l8 h! [6 N: S
  8.       toNano("0.5"),) ?- R" p( I. l
  9.       toNano("1")
      x8 C! w% F; @) a7 A/ y
  10.     );: a. h0 _( o, ]1 }; S; r

  11. 2 E. l! s+ g* V
  12.     expect(withdrawalRequestResult.transactions).toHaveTransaction({
      y$ B; D* W+ [
  13.       from: senderWallet.address,; B! [/ p( t" l  T& M
  14.       to: myContract.address,9 B  D' R7 a% S
  15.       success: false,7 q, P6 U/ {6 L4 }
  16.       exitCode: 103,: \" [/ z4 D' F$ l' t4 m+ l: `
  17.     });
    6 y4 i! _' O7 |% _% r3 z
  18.   });
复制代码
在本次测试中,我们代表发送方钱包而不是所有者钱包发送提款请求(两者的区别在于初始化时我们提供的助记词).
还请注意,我们是如何通过 success: false 和具体的失败原因 exitCode: 103. 为了确保我们做得正确,请看一下我们的合约代码,我们有这样一行代码:
  1. throw_unless(103, equal_slice_bits(sender_address, owner_address));
    4 F7 A; Y7 h! S; u) R
复制代码
我们进行最后一项测试--由于没有余额,提款失败:
  1. it("fails to withdraw funds because lack of balance", async () => {
    ! l, }# P) j' ]; @. G, ~9 w1 m
  2.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(
    ) z8 h9 i, F# Z
  3.       ownerWallet.getSender(),9 G6 E0 |' x5 r. N; S- }
  4.       toNano("0.5"),  i- p4 D1 q* y+ v- X
  5.       toNano("1")- o6 J5 l( L, w; [8 |
  6.     );2 M% O2 _5 X) n8 Y" X

  7. + A$ m" j* A4 N; j7 E  n3 W
  8.     expect(withdrawalRequestResult.transactions).toHaveTransaction({
    $ M- P$ k3 h2 J
  9.       from: ownerWallet.address,
    , q1 l" j- U6 b; V
  10.       to: myContract.address,
    4 L) Q7 {5 s" q% o  u
  11.       success: false,! z* [! l# U& c, I1 D/ E
  12.       exitCode: 104,  M( |6 n, k# o$ V: t
  13.     });3 K, x" ~0 L4 C4 [  q$ ?3 K* b
  14.   });
复制代码
  1. throw_unless(104, balance >= withdraw_amount);2 D1 n. c' `! o7 H5 G
复制代码
就是这样
几章之后,我们将学习如何构建网络客户端,以便与合约进行交互。
+ f, z# d6 ?# H; X% ^" n# d+ C6 }0 Y

$ ?3 j3 Y2 y2 I6 G
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则