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

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

回答

收藏

4.4 存款/提款逻辑测试

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

在本课中,我们将编写一些有趣的测试。
首先,我们要更新之前编写的合约的初始化过程,因为我们引入了一个新变量,它应该存储在 c4 存储器中。
如果您现在尝试运行我们的测试 - yarn test 您可以看到测试将失败。您还将看到发生在我们合约上的交易跟踪,其中一个交易的错误代码为 9. Have a look at the exit codes documentation.
9 - Cell下溢。从片断基元读取数据时,试图读取的位或引用数超过总数。
更新我们的合约包装器
首先,让我们更新我们的合约包装器,以便它能意识到 c4 存储中的第三个参数。也就是说,我们将更新 MainContractConfig 和 mainContractConfigToCell 函数
  1. // ...library imports
    3 K& [1 V: t4 ?1 _

  2. ' P# E  U. G5 s2 k/ b/ M8 T
  3. export type MainContractConfig = {
    5 _6 ]2 [: M* P* n
  4.   number: number;/ k) D: t* `' f# Z
  5.   address: Address;
    - m# L2 E3 Q) d5 O5 o* _' s
  6.   owner_address: Address;
    . p1 N5 e2 x* ?! u+ o8 F
  7. };/ m, K. f4 |$ _& c7 C: ]
  8. % G( `7 q* W' _; l) Q# T
  9. export function mainContractConfigToCell(config: MainContractConfig): Cell {
    2 I$ n3 M0 K+ o% Y0 {! s
  10.   return beginCell()" ?2 Y7 N- F/ j
  11.     .storeUint(config.number, 32)3 D* [" e: o8 V0 Y7 s
  12.     .storeAddress(config.address)8 m( {2 @$ A& ]+ h) F
  13.     .storeAddress(config.owner_address)( d1 @# a# U4 ^7 m
  14.     .endCell();
    - [9 e0 M0 R0 a' L9 h" }. @6 ~
  15. }
    7 E# \3 C" C4 S

  16. 6 i) K$ Z/ |/ `4 K9 F: A, g, _
  17. // ...contact wrapper class
复制代码
封装文件中还有一点需要更新-getData 方法,这样它也会返回 owner_address 我们还将创建新方法 getBalance,以测试存款后余额是否增加:
: g. }6 Z# ^' J5 e9 G0 g  G" K+ C1 e
  1. async getData(provider: ContractProvider) {
    ' t. s4 ?+ l  y5 ^
  2.     const { stack } = await provider.get("get_contract_storage_data", []);
    1 y  k. @+ f' k9 J3 |9 T
  3.     return {
    ( f5 l. H4 Q! W: F$ {2 q' C
  4.       number: stack.readNumber(),( a( Z" x2 u+ @6 A
  5.       recent_sender: stack.readAddress(),* L  i0 `2 }; _( I6 R7 {
  6.       owner_address: stack.readAddress(),
    ' z. O1 |7 t9 q& i+ ?
  7.     };: f" f* |1 k7 V1 G7 ]
  8.   }8 Z% G/ B- ^! [
  9.   4 g* c  ^9 b1 Y3 L2 [' n
  10. async getBalance(provider: ContractProvider) {
    * J! v2 D* r0 n
  11.     const { stack } = await provider.get("balance", []);2 I, A. @3 I- Y
  12.     return {
    7 g& r: C' p0 H8 w
  13.       number: stack.readNumber(),, }: w0 x* y6 {
  14.     };# X" U1 n# h4 M, I& _2 z' l1 j
  15. }
复制代码
  1. // ...library imports% y+ r6 m! z+ o8 L! C& H, z

  2.   c( @% |6 v0 m/ x* v6 \$ T
  3. describe("main.fc contract tests", () => {) c& ]/ e  X1 g
  4.   it("should get the proper most recent sender address", async () => {
    * y$ g7 G0 \5 c2 l% B
  5.     const blockchain = await Blockchain.create();
    ' |, _8 L" N. {# V/ {
  6.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];, n' X( V# L9 l# J

  7. 8 p2 D6 D% B) Z
  8.     const initAddress = await blockchain.treasury("initAddress");
      r0 h% h3 H" y$ k/ B3 V: w
  9.     const ownerAddress = await blockchain.treasury("ownerAddress");/ o) u0 t$ C6 z# Q
  10.     : B# n: ^( `+ @4 _) G0 v* p0 o
  11.     const myContract = blockchain.openContract(! C: q( [! K% e+ i" x) w
  12.       await MainContract.createFromConfig(
    " D# N2 n2 L* g
  13.         {
    ; D  `! b3 j# ?0 V8 H
  14.           number: 0,3 t$ {5 p8 U( M# P" B& r
  15.           address: initAddress.address,
    ( V( y4 `; d$ Q4 t( `
  16.           owner_address: ownerAddress.address, // now we create myContract from 3 parameters
    & ?" I" z5 d( S% l1 N% o
  17.         },4 V- [7 J2 b8 H' T# X# j. W1 E6 c# r
  18.         codeCell
    " e% \8 G# d0 ]: V
  19.       ). o1 ]4 ~1 @- X8 H0 |
  20.     );, P' _% M. t+ A7 |. w

  21. 2 G; J; a6 C& N& y6 S$ ~9 b6 U
  22. // ...rest of testing code
复制代码

- u3 a+ _5 w  i4 W: e
我们引入一个新的金库,它实际上将是合约的所有者,只有这个所有者以后才能提取资金。这些更新在 tests/main.spec.ts 中进行:
  1. // ...library imports
    3 t( Q/ T1 u- T! C
  2. / T. {. L2 ~, Z0 R; ^! T/ b
  3. describe("main.fc contract tests", () => {! Y  g" K" `' [! K
  4.   it("should get the proper most recent sender address", async () => {
    ; F+ @5 P- @9 x) w
  5.     const blockchain = await Blockchain.create();6 l5 l' {: e) @- |' ~
  6.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];8 Y9 k, `+ t* `" W9 e! U5 m

  7. : F7 |, q1 @0 I8 ?
  8.     const initAddress = await blockchain.treasury("initAddress");
    + C6 b% H  I8 A3 L
  9.     const ownerAddress = await blockchain.treasury("ownerAddress");
    - |4 d. P. m+ q6 b) [
  10.     ' F) z" D9 N2 Q) _1 a
  11.     const myContract = blockchain.openContract(
    ( d& P7 `8 H8 o7 c) ~2 c% C' h
  12.       await MainContract.createFromConfig(! Z" U' b( @9 i  T6 m2 s% H
  13.         {
    8 ?0 d' C" ^2 c% @/ Q
  14.           number: 0,
    7 O8 A. z0 v) }* j7 q. Z0 u
  15.           address: initAddress.address,8 r  b% H5 V" ~6 r7 `6 B
  16.           owner_address: ownerAddress.address, // now we create myContract from 3 parameters" l* C+ o, S2 R) U
  17.         },7 |& h. Y" b; i1 j$ l* O
  18.         codeCell
    . y8 U6 o- B) w  z: l
  19.       )
    8 b* J7 q) w9 q9 t& s; D7 }
  20.     );% u" X% |" k2 c' T" R
  21. $ K% A- q/ u" @, N5 a1 t6 @( i
  22. // ...rest of testing code
复制代码
现在我们好了。 yarn test 成功通过我们之前编写的测试。
6 ?8 P4 N+ D  A3 C- D& p- {5 a4 g
存款测试
让我们在 main.spec.ts 文件中再添加几个测试。
由于我们必须在每次新测试前重新启动合约,因此我们还将把合约启动引入 Jest 的 beforeEach 函数:
  1. // We need to additionally import SandboxContract and TreasuryContract- ]0 G" O+ }) W7 q1 Z3 f
  2. import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";5 \/ B* v% i! q5 W
  3. // ... other library imports$ \* {; H- e% i$ T
  4. describe("main.fc contract tests", () => {: `) I  U' ?0 H& B8 [% g% T3 X4 T
  5.   let blockchain: Blockchain;
    * K% m7 j! p. ~7 D8 P( j! `9 B
  6.   let myContract: SandboxContract<MainContract>;
    0 M4 D9 ]& A/ e% L  v1 v: \* l
  7.   let initWallet: SandboxContract<TreasuryContract>;
    * Y- h4 E8 I7 J9 A( J5 h
  8.   let ownerWallet: SandboxContract<TreasuryContract>;: \& H0 M8 v4 t) {

  9. " H5 [' Z! k- `
  10.   beforeEach(async () => {
    $ |6 C: U/ {0 i# E
  11.     blockchain = await Blockchain.create();% A; _8 {2 D' M" x
  12.     initWallet = await blockchain.treasury("initWallet");
    ' _- R- M4 t4 s, A/ i
  13.     ownerWallet = await blockchain.treasury("ownerWallet");
    ! h9 V: ~1 F8 \4 d# D

  14. 3 q& M9 K+ B; |0 C9 O: Q
  15.     const codeCell = Cell.fromBoc(Buffer.from(hex, "hex"))[0];4 `. I/ F% k+ e; u$ x: a

  16. - u3 \9 Q- t- X) U3 e5 z( d
  17.     myContract = blockchain.openContract($ o( i* `# s1 O  _
  18.       await MainContract.createFromConfig(
    $ s& J0 G) _8 K* T& P
  19.         {
    7 [  W3 m6 R+ G- S, Z
  20.           number: 0,
    7 e! K" Y7 L3 d1 F6 D1 ^
  21.           address: initWallet.address,
    7 A- }& o7 D& A
  22.           owner_address: ownerWallet.address,9 T* Q; _3 V9 `& E3 v; y+ B. |- x
  23.         },* B% t: d4 K8 B' s0 a5 H
  24.         codeCell
    8 D* U: h1 ~1 V* J: H! G
  25.       )
    # [% g5 x2 ]% D0 D) W5 `" O
  26.     );4 G$ {5 E4 W2 a) c+ t
  27.   });
    ' D- Q, r, Z2 |: o( G4 u; W3 E

  28. 9 V7 M5 @1 X, V# k& u
  29.   it("should get the proper most recent sender address", async () => {
    , L/ M5 {, ]3 P4 e2 Y, k
  30.     const senderWallet = await blockchain.treasury("sender");
    4 O. K  L, T( {) A2 }: v9 m9 L
  31.   c+ o0 y$ i" P' |  e
  32.     const sentMessageResult = await myContract.sendIncrement(
    ( b( d# V; K1 K8 b; T( Q
  33.       senderWallet.getSender(),
    9 y& ^. X9 y& K; {7 Y8 `# t
  34.       toNano("0.05"),
    : H% B$ n0 K" T. X) i8 Z
  35.       1! Y9 e& o# p1 D' [' A: l! Q5 P1 ]
  36.     );8 E0 {  d4 [8 g" b. Y
  37. * P  p% M* y5 ~2 O$ V# o' t6 l/ I
  38.     expect(sentMessageResult.transactions).toHaveTransaction({/ \- k( F" P  {' J. O6 c: H2 L& `
  39.       from: senderWallet.address,7 r9 x& f  m- U" F; t/ |
  40.       to: myContract.address,
    , _/ g' y" L, z( h
  41.       success: true,
    6 ^# |  S, y8 d+ @5 Q
  42.     });. ]5 S, J7 D( [

  43. 9 `/ k( C4 d. N, Q
  44.     const data = await myContract.getData();
    ) Z, C5 q* e6 H( I+ ]

  45. # g; n9 s& Z) ~6 r
  46.     expect(data.recent_sender.toString()).toBe(senderWallet.address.toString());+ O0 E. J3 Q8 R2 X' {5 `4 |
  47.     expect(data.number).toEqual(1);  r+ J, k. H  n6 A$ F$ L% y5 `; X
  48.   });
    0 Z+ C% T/ W- F' @  C. `: V# O' T
  49.   it("successfully deposits funds", () => {( Y; Q. I$ g' k% m$ C
  50.     // test logic is coming
    , L! w+ A9 r0 ~4 K
  51.   });2 b1 Y9 T9 S; a; p# r& d9 @; v
  52.   it("should return deposit funds as no command is sent", () => {" b( G) S9 b4 U" {3 ?
  53.     // test logic is coming! R7 _" r% o+ c/ J" x8 F9 t) [
  54.   });
    4 o3 \% n8 ]- g. Z
  55.   it("successfully withdraws funds on behalf of owner", () => {  z; H, x/ d/ a: B* |
  56.     // test logic is coming
    5 ~2 T" ^% E! I# p
  57.   });% e7 D1 z# n8 \* Q0 \
  58.   it("fails to withdraw funds on behalf of non-owner", () => {
    $ Z3 M0 Q2 Q( b5 P% R4 t
  59.     // test logic is coming
    8 g/ H/ q& P& e* m3 p2 G: d
  60.   });
    . w! J! f& z: b: K5 U! ?7 B4 W* R. W
  61.   it("fails to withdraw funds because lack of balance", () => {: Q8 y  N) F& Q/ I2 t
  62.     // test logic is coming& M3 l9 p6 O' g! k) p$ B& r1 C
  63.   });4 P9 w( |/ s) O; l& t8 W
  64. });
复制代码
我们只是将第一个测试的部分行移动到了 beforeEach 中,其余的行应留在第一个测试中 it
让我们为存款写一个测试。我们将发送一条 op == 2 的信息,然后检查余额。像往常一样,首先创建一个封装方法,我们将其称为 sendDeposit:
  1. async sendDeposit(provider: ContractProvider, sender: Sender, value: bigint) {* t  u6 i# u4 i
  2.     const msg_body = beginCell(); C+ U6 P; o/ v" L, c6 v' F
  3.       .storeUint(2, 32) // OP code$ [& v6 U& }& `5 p/ E
  4.       .endCell();
    7 @( Q4 Q8 j$ h  L* a# _2 n
  5. # S. Z+ S! d# j) V
  6.     await provider.internal(sender, {
    $ j$ n- Z" b  D- T
  7.       value,
    ) g6 I+ c& ?! I# Y2 g8 J; y4 w  e
  8.       sendMode: SendMode.PAY_GAS_SEPARATELY,% i+ w% C( v  y# D
  9.       body: msg_body,
    9 d4 M. s2 W/ b
  10.     });6 K3 z  K, {" y2 g
  11.   }
复制代码
我们将不详细介绍这种方法,因为它非常简单--我们只需在信息正文中传递一个操作码。
下面是我们如何使用该方法运行存款测试。
  1. it("successfully deposits funds", async () => {8 y0 P3 m2 z; b/ X$ `
  2.     const senderWallet = await blockchain.treasury("sender");( d# P+ N& J& x; `) b/ a/ X
  3. # z7 j; `* o( [, o
  4.     const depositMessageResult = await myContract.sendDeposit(
    5 y7 |- B0 {3 M* n& [: U; c" l* e0 W
  5.       senderWallet.getSender(),$ C! t* b1 E9 e4 A. i) ~% _
  6.       toNano("5")
    % c* w/ @& L+ z- Q! x
  7.     );
    $ y  q5 y  `/ O+ I: _" S+ u- ~
  8. * w; O# }) A, c, Q: ]0 L
  9.     expect(depositMessageResult.transactions).toHaveTransaction({( W, q5 U* |% `. m* k4 |; w* N
  10.       from: senderWallet.address,
    . p3 k$ _0 s+ |( o' ~4 Q
  11.       to: myContract.address,: S& V1 T" m! S9 f# X6 q, U7 j" G- K
  12.       success: true,
    2 n- s/ Z3 H* S# R
  13.     });
    , m7 O4 {& I% v* W" M1 ~0 _7 V9 k
  14. ( f, g& I4 B* j/ E
  15.     const balanceRequest = await myContract.getBalance();& T# ?) V) s* S5 O( z* |8 w/ H* V
  16. $ L4 |2 G/ g% l% f7 [+ X
  17.     expect(balanceRequest.number).toBeGreaterThan(toNano("4.99"));1 A/ {) O  y$ F6 f! H4 }) n
  18.   });
复制代码
请注意我们是如何检查合约余额是否大于 4.99 TON的,因为我们知道手续费会损失一些资金。
我们再写一个存款测试,但这次会出现误报。我们将在没有存款操作码的情况下发送资金,并期待返回交易,因为该操作码未知。
和以往一样,我们还有一个包装器:
  1. async sendNoCodeDeposit(
    9 U8 _* Z  e8 N
  2.     provider: ContractProvider,
    , [, n# G, j' g% f
  3.     sender: Sender,
    : j& N) b0 }; F0 f
  4.     value: bigint! n0 y7 o4 ^5 x, g% ~% J$ l8 e6 n
  5.   ) {
    * a+ h' `( a  R  ]
  6.     const msg_body = beginCell().endCell();
    2 }  j" O( M* Y. W
  7. ( A. b0 t* \, _3 C
  8.     await provider.internal(sender, {
    . A9 O4 o+ Z. ~0 b0 t. {
  9.       value,
    ) v$ ~+ R" w. Y) |& I3 J  w
  10.       sendMode: SendMode.PAY_GAS_SEPARATELY,$ ]/ _/ G% {" m# b, _
  11.       body: msg_body,
    7 o7 H4 x' k3 e, }8 D3 L
  12.     });' S& ?% B# r  }) e
  13.   }
复制代码
下面是测试代码:

7 F: }/ ]$ C9 p! z
  1. it("should return funds as no command is sent", async () => {
    ) ~( j* u  ~* g' c
  2.     const senderWallet = await blockchain.treasury("sender");
    ; Q) _5 s0 c& @) P' N
  3. & a3 T3 E, P( X$ d' j$ v& j; V
  4.     const depositMessageResult = await myContract.sendNoCodeDeposit(6 s% W% \9 D3 K( [) k! U! T" C
  5.       senderWallet.getSender(),2 a9 E! p& \- Z, Q1 J! a* o3 D
  6.       toNano("5")
    # C' J( I7 X- M1 M2 ]$ P  k8 |
  7.     );
    . {2 N% _8 Y4 V; C, v6 X; d% Z
  8. 8 k7 k2 a4 A- Q# {, J) G9 @
  9.     expect(depositMessageResult.transactions).toHaveTransaction({) x( ~3 C" d" H
  10.       from: myContract.address,
    # `% r0 j8 r: ?3 n( j5 Q: D
  11.       to: senderWallet.address,- e. h+ f0 b. q% _
  12.       success: true,* w2 l1 ~7 H, ]( P0 F9 |3 n
  13.     });
    ( i+ ?0 S8 h: K( @1 _% s( m
  14. : y9 F3 l: L: h6 L
  15.     const balanceRequest = await myContract.getBalance();
    - V4 `$ J8 _9 _( @( N  N/ f
  16.   l! e4 C4 T  f9 ]5 ^* v" P) P7 _  F
  17.     expect(balanceRequest.number).toBe(0);) R) k' d6 G; u/ W$ J" o" B
  18. });
复制代码
提款测试
让我们先创建一个用于提款的新包装器:
  1. async sendWithdrawalRequest(7 \; @( I; I! J7 N! p' K
  2.     provider: ContractProvider,
    9 G& H, \8 D' \  P  Y
  3.     sender: Sender,
    ' E6 m/ R9 a3 n) g) B0 B
  4.     value: bigint,
    % U; w+ p) P( i' @! c+ @
  5.     amount: bigint
    / L% x( e% c5 z8 i, J- `, }
  6.   ) {& f( ?) C, V7 t9 g
  7.     const msg_body = beginCell()
    : T8 n; m6 }8 E; Q  W
  8.       .storeUint(3, 32) // OP code9 ^; N) ?% v3 x" {1 M
  9.       .storeCoins(amount)4 b/ }* V( o' \% F$ \6 Z. T
  10.       .endCell();
    8 r" C+ ]# w# B7 A9 @
  11. # A* ?' |1 H) B6 P  ^# h
  12.     await provider.internal(sender, {
    6 W; B; v* v4 Q7 m( A0 `3 Z0 A
  13.       value,
    ( ^, [& `& w- D: k( ], d( w9 |* Q( Z4 h
  14.       sendMode: SendMode.PAY_GAS_SEPARATELY,
    - z" M. }' Y% Y7 |
  15.       body: msg_body,
    9 o9 t) ]3 G% N" a5 @$ S  d! i
  16.     });
    " T% K9 @: ?" Q
  17.   }
复制代码
我们输入适当的 msg_body 和所需的提款 amount 。
我们将进行 3 项不同的测试。让我们一起来看看:
  1. it("successfully withdraws funds on behalf of owner", async () => {! x  u0 s8 b0 L3 _7 p* p
  2.     const senderWallet = await blockchain.treasury("sender");3 j. ^9 B' F! ]1 X6 U* a% f$ `
  3. & x4 Y) @/ T6 s, q" Q" W6 y( K
  4.     await myContract.sendDeposit(senderWallet.getSender(), toNano("5"));; i# g+ Q9 A: l( k  K9 V) Y
  5. 5 H3 {. `1 ^5 w9 Q1 G( G
  6.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(
    5 y2 D! N: A, |9 {8 A& P$ G4 f
  7.       ownerWallet.getSender(),) O' B- a/ H2 k3 ~# i* k* @
  8.       toNano("0.05"),8 z( a8 k. V" g/ h) K
  9.       toNano("1")
    # t7 z4 M) A2 x; T9 l1 W; [
  10.     );
    . n! P9 Z/ Y! ?& q; T8 y9 k1 _
  11. ! \! {3 K; H7 J' J! Z
  12.     expect(withdrawalRequestResult.transactions).toHaveTransaction({! U6 }8 |' @) e4 p* g7 ~% \
  13.       from: myContract.address,
    ! e; _5 `' f6 Z6 p6 z
  14.       to: ownerWallet.address,, O- D  X; `5 N+ X
  15.       success: true,+ G, [1 a+ u- D( o+ e6 u
  16.       value: toNano(1),
    ' H/ ~0 {; h  Z  Y
  17.     });
    + W4 J& b% Q& Y: W& F0 \9 a
  18.   });
复制代码
要成功提款,我们首先要正确存款。然后我们调用 sendWithdrawalRequest 指定我们要提取 1 Ton。请注意,0.05 Ton只是为了支付费用而指定的信息值。/ J% R9 Z1 E% K9 s' I5 ~
  1. it("fails to withdraw funds on behalf of not-owner", async () => {
    * x8 K4 Y5 c& q* m- K5 V) D& f+ S
  2.     const senderWallet = await blockchain.treasury("sender");  W  y) {* t, f# ]" c

  3. * I# I7 D% T: h6 ~
  4.     await myContract.sendDeposit(senderWallet.getSender(), toNano("5"));
    . N# `! c- F# ]6 M2 Q

  5. - e& @0 B8 {8 Q' T/ J
  6.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(# ]8 p/ h  n9 ^( s
  7.       senderWallet.getSender(),
    9 `7 q/ s* z; M0 u9 }* z) G: L
  8.       toNano("0.5"),
    7 o5 K0 {! E+ l! O3 d7 Q
  9.       toNano("1")( ^; V  t1 H: F
  10.     );& @$ I8 Y! ?2 U

  11. * F+ u0 G9 F  Z& F, `. }
  12.     expect(withdrawalRequestResult.transactions).toHaveTransaction({
    ' e3 }; C8 V3 I$ C7 R
  13.       from: senderWallet.address,
    5 r) Y8 R* s$ a
  14.       to: myContract.address,; e. E* U" s7 ]% C
  15.       success: false,
    , T" B9 w; {  p  z! [1 G. T
  16.       exitCode: 103,8 |  W& [+ x4 j* O$ f9 f- A8 g
  17.     });
    , r5 d6 j7 i# c) k
  18.   });
复制代码
在本次测试中,我们代表发送方钱包而不是所有者钱包发送提款请求(两者的区别在于初始化时我们提供的助记词).
还请注意,我们是如何通过 success: false 和具体的失败原因 exitCode: 103. 为了确保我们做得正确,请看一下我们的合约代码,我们有这样一行代码:
  1. throw_unless(103, equal_slice_bits(sender_address, owner_address));
    - W9 s( y3 S1 |$ |! u
复制代码
我们进行最后一项测试--由于没有余额,提款失败:
  1. it("fails to withdraw funds because lack of balance", async () => {% n( e: A( a3 d1 \$ [: c
  2.     const withdrawalRequestResult = await myContract.sendWithdrawalRequest(
    + n- c$ }6 u" f8 M; t
  3.       ownerWallet.getSender(),$ s! i+ _8 x" q
  4.       toNano("0.5"),
    # a; r" l* @) n+ d+ f5 R, i
  5.       toNano("1")
    ) F+ P8 V, m( z1 ]
  6.     );
    . s2 d( K$ H+ t2 s2 T% e
  7. 3 M1 g# ?& I8 R$ c
  8.     expect(withdrawalRequestResult.transactions).toHaveTransaction({
    9 H0 @9 A0 i3 E! J1 n( u# B6 v3 R
  9.       from: ownerWallet.address,
    - g# B. \& A' F+ J
  10.       to: myContract.address,; Q7 o2 ?2 _3 h( {6 Y
  11.       success: false,
    0 \! G3 e8 T. y# a/ J# j8 w: p% M
  12.       exitCode: 104,* r* P  A2 B- ]( \* M
  13.     });. i9 ], V" A8 {) N5 f' H. A' p
  14.   });
复制代码
  1. throw_unless(104, balance >= withdraw_amount);
    . H, t+ k- ]( H: b5 E
复制代码
就是这样
几章之后,我们将学习如何构建网络客户端,以便与合约进行交互。

* c  o, {: d2 }' t) M; Z# i2 s" t
- h- _( T7 j1 y
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则