@layerzerolabs/layerzero-v2-ton 3.0.12-ton.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +15 -0
  3. package/build/AllStorages.boc +0 -0
  4. package/build/AllStorages.compiled.json +1 -0
  5. package/build/AllStorages.fif +4164 -0
  6. package/build/AllStorages.test.boc +0 -0
  7. package/build/AllStorages.test.compiled.json +1 -0
  8. package/build/AllStorages.test.fif +1831 -0
  9. package/build/BaseContract.test.boc +0 -0
  10. package/build/BaseContract.test.compiled.json +1 -0
  11. package/build/BaseContract.test.fif +3553 -0
  12. package/build/Channel.boc +0 -0
  13. package/build/Channel.compiled.json +1 -0
  14. package/build/Channel.fif +5001 -0
  15. package/build/Channel.permissions.test.boc +0 -0
  16. package/build/Channel.permissions.test.compiled.json +1 -0
  17. package/build/Channel.permissions.test.fif +7569 -0
  18. package/build/ChannelBurn.test.boc +0 -0
  19. package/build/ChannelBurn.test.compiled.json +1 -0
  20. package/build/ChannelBurn.test.fif +7454 -0
  21. package/build/ChannelCommitPacket.test.boc +0 -0
  22. package/build/ChannelCommitPacket.test.compiled.json +1 -0
  23. package/build/ChannelCommitPacket.test.fif +7981 -0
  24. package/build/ChannelConfig.test.boc +0 -0
  25. package/build/ChannelConfig.test.compiled.json +1 -0
  26. package/build/ChannelConfig.test.fif +7442 -0
  27. package/build/ChannelInitialize.test.boc +0 -0
  28. package/build/ChannelInitialize.test.compiled.json +1 -0
  29. package/build/ChannelInitialize.test.fif +7289 -0
  30. package/build/ChannelMsglibIntegration.test.boc +0 -0
  31. package/build/ChannelMsglibIntegration.test.compiled.json +1 -0
  32. package/build/ChannelMsglibIntegration.test.fif +7404 -0
  33. package/build/ChannelMsglibSendCallback.test.boc +0 -0
  34. package/build/ChannelMsglibSendCallback.test.compiled.json +1 -0
  35. package/build/ChannelMsglibSendCallback.test.fif +7711 -0
  36. package/build/ChannelNilify.test.boc +0 -0
  37. package/build/ChannelNilify.test.compiled.json +1 -0
  38. package/build/ChannelNilify.test.fif +7672 -0
  39. package/build/ChannelReceive.test.boc +0 -0
  40. package/build/ChannelReceive.test.compiled.json +1 -0
  41. package/build/ChannelReceive.test.fif +7702 -0
  42. package/build/ChannelReceiveCallback.test.boc +0 -0
  43. package/build/ChannelReceiveCallback.test.compiled.json +1 -0
  44. package/build/ChannelReceiveCallback.test.fif +7549 -0
  45. package/build/ChannelReceiveView.test.boc +0 -0
  46. package/build/ChannelReceiveView.test.compiled.json +1 -0
  47. package/build/ChannelReceiveView.test.fif +7352 -0
  48. package/build/ChannelSend.test.boc +0 -0
  49. package/build/ChannelSend.test.compiled.json +1 -0
  50. package/build/ChannelSend.test.fif +7658 -0
  51. package/build/Classlib.test.boc +0 -0
  52. package/build/Classlib.test.compiled.json +1 -0
  53. package/build/Classlib.test.fif +4728 -0
  54. package/build/Connection.boc +0 -0
  55. package/build/Connection.compiled.json +1 -0
  56. package/build/Connection.fif +3503 -0
  57. package/build/Connection.test.boc +0 -0
  58. package/build/Connection.test.compiled.json +1 -0
  59. package/build/Connection.test.fif +6575 -0
  60. package/build/Controller.assertions.test.boc +0 -0
  61. package/build/Controller.assertions.test.compiled.json +1 -0
  62. package/build/Controller.assertions.test.fif +6130 -0
  63. package/build/Controller.boc +0 -0
  64. package/build/Controller.compiled.json +1 -0
  65. package/build/Controller.fif +3195 -0
  66. package/build/Controller.permissions.test.boc +0 -0
  67. package/build/Controller.permissions.test.compiled.json +1 -0
  68. package/build/Controller.permissions.test.fif +6237 -0
  69. package/build/Controller.test.boc +0 -0
  70. package/build/Controller.test.compiled.json +1 -0
  71. package/build/Controller.test.fif +6400 -0
  72. package/build/Counter.boc +0 -0
  73. package/build/Counter.compiled.json +1 -0
  74. package/build/Counter.fif +4809 -0
  75. package/build/Counter.permissions.test.boc +0 -0
  76. package/build/Counter.permissions.test.compiled.json +1 -0
  77. package/build/Counter.permissions.test.fif +7106 -0
  78. package/build/Counter.setters.test.boc +0 -0
  79. package/build/Counter.setters.test.compiled.json +1 -0
  80. package/build/Counter.setters.test.fif +7083 -0
  81. package/build/Counter.test.boc +0 -0
  82. package/build/Counter.test.compiled.json +1 -0
  83. package/build/Counter.test.fif +7540 -0
  84. package/build/Dvn.boc +0 -0
  85. package/build/Dvn.compiled.json +1 -0
  86. package/build/Dvn.fif +2923 -0
  87. package/build/Dvn.test.boc +0 -0
  88. package/build/Dvn.test.compiled.json +1 -0
  89. package/build/Dvn.test.fif +5753 -0
  90. package/build/Endpoint.boc +0 -0
  91. package/build/Endpoint.compiled.json +1 -0
  92. package/build/Endpoint.fif +3694 -0
  93. package/build/Endpoint.permissions.test.boc +0 -0
  94. package/build/Endpoint.permissions.test.compiled.json +1 -0
  95. package/build/Endpoint.permissions.test.fif +6211 -0
  96. package/build/Endpoint.test.boc +0 -0
  97. package/build/Endpoint.test.compiled.json +1 -0
  98. package/build/Endpoint.test.fif +6899 -0
  99. package/build/EndpointSetEpConfigDefaults.test.boc +0 -0
  100. package/build/EndpointSetEpConfigDefaults.test.compiled.json +1 -0
  101. package/build/EndpointSetEpConfigDefaults.test.fif +6529 -0
  102. package/build/Executor.boc +0 -0
  103. package/build/Executor.compiled.json +1 -0
  104. package/build/Executor.fif +2731 -0
  105. package/build/Executor.test.boc +0 -0
  106. package/build/Executor.test.compiled.json +1 -0
  107. package/build/Executor.test.fif +5822 -0
  108. package/build/LzClasses.test.boc +0 -0
  109. package/build/LzClasses.test.compiled.json +1 -0
  110. package/build/LzClasses.test.fif +4457 -0
  111. package/build/LzUtil.test.boc +0 -0
  112. package/build/LzUtil.test.compiled.json +1 -0
  113. package/build/LzUtil.test.fif +1831 -0
  114. package/build/MsgData.test.boc +0 -0
  115. package/build/MsgData.test.compiled.json +1 -0
  116. package/build/MsgData.test.fif +4318 -0
  117. package/build/MsglibPacketCodec.test.boc +0 -0
  118. package/build/MsglibPacketCodec.test.compiled.json +1 -0
  119. package/build/MsglibPacketCodec.test.fif +4851 -0
  120. package/build/MultiSig.boc +0 -0
  121. package/build/MultiSig.compiled.json +1 -0
  122. package/build/MultiSig.fif +727 -0
  123. package/build/MultiSigOrder.boc +0 -0
  124. package/build/MultiSigOrder.compiled.json +1 -0
  125. package/build/MultiSigOrder.fif +650 -0
  126. package/build/PipelinedOutOfOrder.test.boc +0 -0
  127. package/build/PipelinedOutOfOrder.test.compiled.json +1 -0
  128. package/build/PipelinedOutOfOrder.test.fif +2188 -0
  129. package/build/SmlConnection.boc +0 -0
  130. package/build/SmlConnection.compiled.json +1 -0
  131. package/build/SmlConnection.fif +2517 -0
  132. package/build/SmlConnection.permissions.test.boc +0 -0
  133. package/build/SmlConnection.permissions.test.compiled.json +1 -0
  134. package/build/SmlConnection.permissions.test.fif +5497 -0
  135. package/build/SmlConnection.test.boc +0 -0
  136. package/build/SmlConnection.test.compiled.json +1 -0
  137. package/build/SmlConnection.test.fif +5494 -0
  138. package/build/SmlManager.boc +0 -0
  139. package/build/SmlManager.compiled.json +1 -0
  140. package/build/SmlManager.fif +3904 -0
  141. package/build/SmlManager.permissions.test.boc +0 -0
  142. package/build/SmlManager.permissions.test.compiled.json +1 -0
  143. package/build/SmlManager.permissions.test.fif +6018 -0
  144. package/build/SmlManager.test.boc +0 -0
  145. package/build/SmlManager.test.compiled.json +1 -0
  146. package/build/SmlManager.test.fif +6047 -0
  147. package/build/Uln.boc +0 -0
  148. package/build/Uln.compiled.json +1 -0
  149. package/build/Uln.fif +4841 -0
  150. package/build/Uln.test.boc +0 -0
  151. package/build/Uln.test.compiled.json +1 -0
  152. package/build/Uln.test.fif +7077 -0
  153. package/build/UlnManager.boc +0 -0
  154. package/build/UlnManager.compiled.json +1 -0
  155. package/build/UlnManager.fif +3851 -0
  156. package/build/UlnManager.test.boc +0 -0
  157. package/build/UlnManager.test.compiled.json +1 -0
  158. package/build/UlnManager.test.fif +6571 -0
  159. package/build/UlnReceiveConfig.test.boc +0 -0
  160. package/build/UlnReceiveConfig.test.compiled.json +1 -0
  161. package/build/UlnReceiveConfig.test.fif +4413 -0
  162. package/build/UlnSend.test.boc +0 -0
  163. package/build/UlnSend.test.compiled.json +1 -0
  164. package/build/UlnSend.test.fif +6576 -0
  165. package/build/UlnSendConfig.test.boc +0 -0
  166. package/build/UlnSendConfig.test.compiled.json +1 -0
  167. package/build/UlnSendConfig.test.fif +4431 -0
  168. package/build/UlnSendWorkerFactory.test.boc +0 -0
  169. package/build/UlnSendWorkerFactory.test.compiled.json +1 -0
  170. package/build/UlnSendWorkerFactory.test.fif +6683 -0
  171. package/build/UlnUtil.test.boc +0 -0
  172. package/build/UlnUtil.test.compiled.json +1 -0
  173. package/build/UlnUtil.test.fif +5873 -0
  174. package/build/WorkerCore.test.boc +0 -0
  175. package/build/WorkerCore.test.compiled.json +1 -0
  176. package/build/WorkerCore.test.fif +5630 -0
  177. package/build/ZroMinter.boc +0 -0
  178. package/build/ZroMinter.compiled.json +1 -0
  179. package/build/ZroMinter.fif +2300 -0
  180. package/build/ZroWallet.boc +0 -0
  181. package/build/ZroWallet.compiled.json +1 -0
  182. package/build/ZroWallet.fif +2471 -0
  183. package/package.json +64 -0
  184. package/src/classes/lz/Attestation.fc +23 -0
  185. package/src/classes/lz/Config.fc +23 -0
  186. package/src/classes/lz/EpConfig.fc +91 -0
  187. package/src/classes/lz/MsglibInfo.fc +31 -0
  188. package/src/classes/lz/Packet.fc +202 -0
  189. package/src/classes/lz/Path.fc +56 -0
  190. package/src/classes/lz/ReceiveEpConfig.fc +24 -0
  191. package/src/classes/lz/SendEpConfig.fc +18 -0
  192. package/src/classes/lz/SmlJobAssigned.fc +20 -0
  193. package/src/classes/lz/Worker.fc +32 -0
  194. package/src/classes/msgdata/AddMsglib.fc +18 -0
  195. package/src/classes/msgdata/Amount.fc +16 -0
  196. package/src/classes/msgdata/Bool.fc +16 -0
  197. package/src/classes/msgdata/ChannelNonceInfo.fc +18 -0
  198. package/src/classes/msgdata/ClaimUnaccountedPoolFunds.fc +0 -0
  199. package/src/classes/msgdata/CoinsAmount.fc +16 -0
  200. package/src/classes/msgdata/CounterIncrement.fc +24 -0
  201. package/src/classes/msgdata/Deploy.fc +20 -0
  202. package/src/classes/msgdata/ExtendedMd.fc +20 -0
  203. package/src/classes/msgdata/GetMsglibCallback.fc +18 -0
  204. package/src/classes/msgdata/InitEndpoint.fc +16 -0
  205. package/src/classes/msgdata/InitSmlConnection.fc +16 -0
  206. package/src/classes/msgdata/InitUlnConnection.fc +18 -0
  207. package/src/classes/msgdata/LzReceiveStatus.fc +58 -0
  208. package/src/classes/msgdata/LzSend.fc +58 -0
  209. package/src/classes/msgdata/MdAddress.fc +18 -0
  210. package/src/classes/msgdata/MdEid.fc +18 -0
  211. package/src/classes/msgdata/MdObj.fc +18 -0
  212. package/src/classes/msgdata/MessagingReceipt.fc +22 -0
  213. package/src/classes/msgdata/MsglibSendCallback.fc +113 -0
  214. package/src/classes/msgdata/Nonce.fc +16 -0
  215. package/src/classes/msgdata/OptionsExtended.fc +20 -0
  216. package/src/classes/msgdata/OptionsV1.fc +27 -0
  217. package/src/classes/msgdata/OptionsV2.fc +34 -0
  218. package/src/classes/msgdata/PacketId.fc +18 -0
  219. package/src/classes/msgdata/PacketSent.fc +39 -0
  220. package/src/classes/msgdata/SetAddress.fc +16 -0
  221. package/src/classes/msgdata/SetEpConfig.fc +33 -0
  222. package/src/classes/msgdata/SetPeer.fc +18 -0
  223. package/src/classes/msgdata/SetSmlManagerConfig.fc +18 -0
  224. package/src/funC++/abstract/contractMainAbstract.fc +3 -0
  225. package/src/funC++/abstract/handlerAbstract.fc +12 -0
  226. package/src/funC++/actions/call.fc +51 -0
  227. package/src/funC++/actions/deploy.fc +118 -0
  228. package/src/funC++/actions/destroy.fc +28 -0
  229. package/src/funC++/actions/dispatch.fc +57 -0
  230. package/src/funC++/actions/event.fc +69 -0
  231. package/src/funC++/actions/payment.fc +52 -0
  232. package/src/funC++/actions/sendJettons.fc +76 -0
  233. package/src/funC++/actions/utils.fc +49 -0
  234. package/src/funC++/baseInterface.fc +16 -0
  235. package/src/funC++/classlib.fc +819 -0
  236. package/src/funC++/constants.fc +64 -0
  237. package/src/funC++/contractMain.fc +84 -0
  238. package/src/funC++/dataStructures/DeterministicInsertionCircularQueue.fc +155 -0
  239. package/src/funC++/dataStructures/PipelinedOutOfOrder.fc +93 -0
  240. package/src/funC++/handlerCore.fc +30 -0
  241. package/src/funC++/stdlib.fc +625 -0
  242. package/src/funC++/stringlib.fc +75 -0
  243. package/src/funC++/txnContext.fc +126 -0
  244. package/src/funC++/utils.fc +119 -0
  245. package/src/jettons/zro/minter.fc +120 -0
  246. package/src/jettons/zro/op-codes.fc +10 -0
  247. package/src/jettons/zro/params.fc +18 -0
  248. package/src/jettons/zro/utils.fc +33 -0
  249. package/src/jettons/zro/wallet.fc +261 -0
  250. package/tests/baseContractTest.fc +192 -0
  251. package/tests/testMain.fc +135 -0
@@ -0,0 +1,261 @@
1
+ #include "op-codes.fc";
2
+ #include "utils.fc";
3
+ #include "../../../node_modules/@ston-fi/funcbox/autoload.fc";
4
+
5
+ ;; Jetton Wallet Smart Contract
6
+
7
+ {-
8
+
9
+ NOTE that this tokens can be transferred within the same workchain.
10
+
11
+ This is suitable for most tokens, if you need tokens transferable between workchains there are two solutions:
12
+
13
+ 1) use more expensive but universal function to calculate message forward fee for arbitrary destination (see `misc/forward-fee-calc.cs`)
14
+
15
+ 2) use token holder proxies in target workchain (that way even 'non-universal' token can be used from any workchain)
16
+
17
+ -}
18
+
19
+ int min_tons_for_storage() asm "10000000 PUSHINT"; ;; 0.01 TON
20
+ ;; Note that 2 * gas_consumptions is expected to be able to cover fees on both wallets (sender and receiver)
21
+ ;; and also constant fees on inter-wallet interaction, in particular fwd fee on state_init transfer
22
+ ;; that means that you need to reconsider this fee when:
23
+ ;; a) jetton logic become more gas-heavy
24
+ ;; b) jetton-wallet code (sent with inter-wallet message) become larger or smaller
25
+ ;; c) global fee changes / different workchain
26
+ int gas_consumption() asm "15000000 PUSHINT"; ;; 0.015 TON
27
+
28
+ {-
29
+ Storage
30
+ storage#_ balance:Coins owner_address:MsgAddressInt jetton_master_address:MsgAddressInt jetton_wallet_code:^Cell = Storage;
31
+ -}
32
+
33
+ (int, slice, slice, cell) load_data() inline {
34
+ slice ds = get_data().begin_parse();
35
+ return (ds~load_coins(), ds~load_msg_addr(), ds~load_msg_addr(), ds~load_ref());
36
+ }
37
+
38
+ () save_data (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) impure inline {
39
+ set_data(pack_jetton_wallet_data(balance, owner_address, jetton_master_address, jetton_wallet_code));
40
+ }
41
+
42
+ {-
43
+ transfer query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress
44
+ response_destination:MsgAddress custom_payload:(Maybe ^Cell)
45
+ forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell)
46
+ = InternalMsgBody;
47
+ internal_transfer query_id:uint64 amount:(VarUInteger 16) from:MsgAddress
48
+ response_address:MsgAddress
49
+ forward_ton_amount:(VarUInteger 16)
50
+ forward_payload:(Either Cell ^Cell)
51
+ = InternalMsgBody;
52
+ -}
53
+
54
+ () send_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {
55
+ int query_id = in_msg_body~load_uint(64);
56
+ int jetton_amount = in_msg_body~load_coins();
57
+ slice to_owner_address = in_msg_body~load_msg_addr();
58
+ force_chain(BASECHAIN, to_owner_address, 101);
59
+
60
+ (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
61
+ balance -= jetton_amount;
62
+
63
+ throw_unless(705, equal_slices(owner_address, sender_address));
64
+ throw_unless(706, balance >= 0);
65
+
66
+ cell state_init = calculate_jetton_wallet_state_init(to_owner_address, jetton_master_address, jetton_wallet_code);
67
+ slice to_wallet_address = calculate_jetton_wallet_address(state_init);
68
+ slice response_address = in_msg_body~load_msg_addr();
69
+ cell custom_payload = in_msg_body~load_dict();
70
+ int forward_ton_amount = in_msg_body~load_coins();
71
+ throw_unless(708, slice_bits(in_msg_body) >= 1);
72
+ slice either_forward_payload = in_msg_body;
73
+ var msg = begin_cell()
74
+ .store_uint(0x18, 6)
75
+ .store_slice(to_wallet_address)
76
+ .store_coins(0)
77
+ .store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)
78
+ .store_ref(state_init);
79
+ var msg_body = begin_cell()
80
+ .store_uint(op::internal_transfer(), 32)
81
+ .store_uint(query_id, 64)
82
+ .store_coins(jetton_amount)
83
+ .store_slice(owner_address)
84
+ .store_slice(response_address)
85
+ .store_coins(forward_ton_amount)
86
+ .store_slice(either_forward_payload)
87
+ .end_cell();
88
+
89
+ msg = msg.store_ref(msg_body);
90
+ int fwd_count = forward_ton_amount ? 2 : 1;
91
+ throw_unless(709, msg_value >
92
+ forward_ton_amount +
93
+ ;; 3 messages: wal1->wal2, wal2->owner, wal2->response
94
+ ;; but last one is optional (it is ok if it fails)
95
+ fwd_count * fwd_fee +
96
+ (2 * gas_consumption() + min_tons_for_storage()));
97
+ ;; universal message send fee calculation may be activated here
98
+ ;; by using this instead of fwd_fee
99
+ ;; msg_fwd_fee(to_wallet, msg_body, state_init, 15)
100
+
101
+ send_raw_message(msg.end_cell(), 64); ;; revert on errors
102
+ save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
103
+ }
104
+
105
+ {-
106
+ internal_transfer query_id:uint64 amount:(VarUInteger 16) from:MsgAddress
107
+ response_address:MsgAddress
108
+ forward_ton_amount:(VarUInteger 16)
109
+ forward_payload:(Either Cell ^Cell)
110
+ = InternalMsgBody;
111
+ -}
112
+
113
+ () receive_tokens (slice in_msg_body, slice sender_address, int my_ton_balance, int fwd_fee, int msg_value) impure {
114
+ ;; NOTE we can not allow fails in action phase since in that case there will be
115
+ ;; no bounce. Thus check and throw in computation phase.
116
+ (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
117
+ int query_id = in_msg_body~load_uint(64);
118
+ int jetton_amount = in_msg_body~load_coins();
119
+ balance += jetton_amount;
120
+ slice from_address = in_msg_body~load_msg_addr();
121
+ slice response_address = in_msg_body~load_msg_addr();
122
+ throw_unless(707,
123
+ equal_slices(jetton_master_address, sender_address)
124
+ |
125
+ equal_slices(calculate_user_jetton_wallet_address(from_address, jetton_master_address, jetton_wallet_code), sender_address)
126
+ );
127
+ int forward_ton_amount = in_msg_body~load_coins();
128
+
129
+ int ton_balance_before_msg = my_ton_balance - msg_value;
130
+ int storage_fee = min_tons_for_storage() - min(ton_balance_before_msg, min_tons_for_storage());
131
+ msg_value -= (storage_fee + gas_consumption());
132
+ slice either_forward_payload = in_msg_body;
133
+ if(forward_ton_amount) {
134
+ msg_value -= (forward_ton_amount + fwd_fee);
135
+
136
+ var msg_body = begin_cell()
137
+ .store_uint(op::transfer_notification(), 32)
138
+ .store_uint(query_id, 64)
139
+ .store_coins(jetton_amount)
140
+ .store_slice(from_address)
141
+ .store_slice(either_forward_payload)
142
+ .end_cell();
143
+
144
+ var msg = begin_cell()
145
+ .store_uint(0x10, 6) ;; we should not bounce here cause receiver can have uninitialized contract
146
+ .store_slice(owner_address)
147
+ .store_coins(forward_ton_amount)
148
+ .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
149
+ .store_ref(msg_body);
150
+
151
+ send_raw_message(msg.end_cell(), 1);
152
+ }
153
+
154
+ if ((response_address.preload_uint(2) != 0) & (msg_value > 0)) {
155
+
156
+ var msg_body = begin_cell()
157
+ .store_uint(op::excesses, 32)
158
+ .store_uint(query_id, 64)
159
+ .store_coins(jetton_amount)
160
+ .store_slice(from_address)
161
+ .store_slice(either_forward_payload)
162
+ .end_cell();
163
+
164
+ var msg = begin_cell()
165
+ .store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000
166
+ .store_slice(response_address)
167
+ .store_coins(msg_value)
168
+ .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
169
+ .store_ref(msg_body);
170
+ send_raw_message(msg.end_cell(), 2);
171
+ }
172
+
173
+ save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
174
+ }
175
+
176
+ () burn_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {
177
+ ;; NOTE we can not allow fails in action phase since in that case there will be
178
+ ;; no bounce. Thus check and throw in computation phase.
179
+ (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
180
+ int query_id = in_msg_body~load_uint(64);
181
+ int jetton_amount = in_msg_body~load_coins();
182
+ slice response_address = in_msg_body~load_msg_addr();
183
+ ;; ignore custom payload
184
+ ;; slice custom_payload = in_msg_body~load_dict();
185
+ balance -= jetton_amount;
186
+ throw_unless(705, equal_slices(owner_address, sender_address));
187
+ throw_unless(706, balance >= 0);
188
+ throw_unless(707, msg_value > fwd_fee + 2 * gas_consumption());
189
+
190
+ var msg_body = begin_cell()
191
+ .store_uint(op::burn_notification(), 32)
192
+ .store_uint(query_id, 64)
193
+ .store_coins(jetton_amount)
194
+ .store_slice(owner_address)
195
+ .store_slice(response_address)
196
+ .end_cell();
197
+
198
+ var msg = begin_cell()
199
+ .store_uint(0x18, 6)
200
+ .store_slice(jetton_master_address)
201
+ .store_coins(0)
202
+ .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)
203
+ .store_ref(msg_body);
204
+
205
+ send_raw_message(msg.end_cell(), 64);
206
+
207
+ save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
208
+ }
209
+
210
+ () on_bounce (slice in_msg_body) impure {
211
+ in_msg_body~skip_bits(32); ;; 0xFFFFFFFF
212
+ (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();
213
+ int op = in_msg_body~load_uint(32);
214
+ throw_unless(709, (op == op::internal_transfer()) | (op == op::burn_notification()));
215
+ int query_id = in_msg_body~load_uint(64);
216
+ int jetton_amount = in_msg_body~load_coins();
217
+ balance += jetton_amount;
218
+ save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);
219
+ }
220
+
221
+ () recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
222
+ if (in_msg_body.slice_empty?()) { ;; ignore empty messages
223
+ return ();
224
+ }
225
+
226
+ slice cs = in_msg_full.begin_parse();
227
+ int flags = cs~load_uint(4);
228
+ if (flags & 1) {
229
+ on_bounce(in_msg_body);
230
+ return ();
231
+ }
232
+ slice sender_address = cs~load_msg_addr();
233
+ cs~load_msg_addr(); ;; skip dst
234
+ cs~load_coins(); ;; skip value
235
+ cs~skip_bits(1); ;; skip extracurrency collection
236
+ cs~load_coins(); ;; skip ihr_fee
237
+ int fwd_fee = muldiv(cs~load_coins(), 3, 2); ;; we use message fwd_fee for estimation of forward_payload costs
238
+
239
+ int op = in_msg_body~load_uint(32);
240
+
241
+ if (op == op::transfer()) { ;; outgoing transfer
242
+ send_tokens(in_msg_body, sender_address, msg_value, fwd_fee);
243
+ return ();
244
+ }
245
+
246
+ if (op == op::internal_transfer()) { ;; incoming transfer
247
+ receive_tokens(in_msg_body, sender_address, my_balance, fwd_fee, msg_value);
248
+ return ();
249
+ }
250
+
251
+ if (op == op::burn()) { ;; burn
252
+ burn_tokens(in_msg_body, sender_address, msg_value, fwd_fee);
253
+ return ();
254
+ }
255
+
256
+ throw(0xffff);
257
+ }
258
+
259
+ (int, slice, slice, cell) get_wallet_data() method_id {
260
+ return load_data();
261
+ }
@@ -0,0 +1,192 @@
1
+ #include "./testMain.fc";
2
+ #include "../src/funC++/classlib.fc";
3
+ #include "../src/funC++/stringlib.fc";
4
+ #include "../src/funC++/utils.fc";
5
+
6
+ #include "../src/funC++/actions/event.fc";
7
+ #include "../src/funC++/actions/sendJettons.fc";
8
+ #include "../src/funC++/actions/call.fc";
9
+ #include "../src/funC++/actions/deploy.fc";
10
+ #include "../src/funC++/actions/destroy.fc";
11
+ #include "../src/funC++/actions/dispatch.fc";
12
+ #include "../src/funC++/actions/payment.fc";
13
+
14
+ ;;; ===============================INTERFACE FUNCTIONS===========================
15
+ int _callCheckPermissions(int op, cell $md) impure;
16
+
17
+ ;;; ===============================BASE TEST INTERFACE IMPLEMENTATIONS===========================
18
+
19
+ ;; authenticates and initializes a base storage for an LZ contract
20
+ () forceAuthenticate(int base_storage_idx) impure;
21
+
22
+ cell createInitializedStorage() impure;
23
+
24
+ cell baseTest::prepare(tuple args) impure {
25
+ return createInitializedStorage();
26
+ }
27
+
28
+ ;;; ===============================HELPER FUNCTIONS===========================
29
+ () spoofCaller(int address_hashpart) impure inline {
30
+ setCaller(address_hashpart);
31
+ }
32
+
33
+ ;;; ===============================TEST HANDLERS===============================
34
+ ;; An empty test, when inserted at the top of a test list it allows initialization of storage
35
+ ;; then returns success. Helps to avoid OOG for big contracts
36
+ (int, slice) initializeTestStorage(cell $storage) impure {
37
+ return (TEST_SUCCESS, "");
38
+ }
39
+
40
+ ;; int TEST_SUCCESS or TEST_FAILURE, slice (optional) error_message
41
+ (int, slice) test::handler::shouldPass((cell -> tuple) handler, cell $md, tuple expectedActions, cell $expectedStorage, tuple expectedTxnContext) impure {
42
+ ;; Checkpoint the current gas meter
43
+ int start = get_gas_consumed();
44
+
45
+ ;; Run the actual handler
46
+ tuple actions = handler($md);
47
+
48
+ ;; Optionally profile gas
49
+ if (do_profile) {
50
+ ;; Should not inline gasConsumed because the string construction costs gas
51
+ int gasConsumed = get_gas_consumed() - start;
52
+ ~strdump(base_error_msg.str::concat(" consumed gas: ").str::concatInt(gasConsumed));
53
+ }
54
+
55
+ ;; Check the number of actions matches the expected
56
+ int numActions = actions.tlen();
57
+ if (numActions != expectedActions.tlen()) {
58
+ return (
59
+ TEST_FAILED,
60
+ "action length incorrect:"
61
+ .str::concatInt(actions.tlen())
62
+ .str::concat(" !== ")
63
+ .str::concatInt(expectedActions.tlen())
64
+ );
65
+ }
66
+
67
+ if (actions.int_at(0) != expectedActions.int_at(0)) {
68
+ return (TEST_FAILED, "action value outflow incorrect");
69
+ }
70
+
71
+ ;; Check that each action matches the expected action
72
+ int index = 1;
73
+ tuple terminalIndices = empty_tuple();
74
+ while (index < numActions) {
75
+ tuple actualAction = actions.tuple_at(index);
76
+ tuple expectedAction = expectedActions.tuple_at(index);
77
+ if (actualAction.int_at(0) != expectedAction.int_at(0)) {
78
+ test::throwError("action type incorrect: ".str::concatInt(index));
79
+ }
80
+ int actionType = actualAction.int_at(0);
81
+ int equal = false;
82
+
83
+ if (actionType == action::destroy::NAME) {
84
+ terminalIndices = terminalIndices.tpush(index);
85
+ equal = action::destroy::equals(actualAction, expectedAction);
86
+ } elseif (actionType == action::deploy::NAME) {
87
+ terminalIndices = terminalIndices.tpush(index);
88
+ equal = action::deploy::equals(actualAction, expectedAction);
89
+ } elseif (actionType == action::call::NAME) {
90
+ terminalIndices = terminalIndices.tpush(index);
91
+ equal = action::call::equals(actualAction, expectedAction);
92
+ } elseif (actionType == action::dispatch::NAME) {
93
+ equal = action::dispatch::equals(actualAction, expectedAction);
94
+ } elseif (actionType == action::payment::NAME) {
95
+ equal = action::payment::equals(actualAction, expectedAction);
96
+ } elseif (actionType == action::event::NAME) {
97
+ equal = action::event::equals(actualAction, expectedAction);
98
+ } elseif (actionType == action::sendJettons::NAME) {
99
+ equal = action::sendJettons::equals(actualAction, expectedAction);
100
+ }
101
+ ifnot (equal) {
102
+ test::throwError("action incorrect: ".str::concatInt(index));
103
+ }
104
+ index += 1;
105
+ }
106
+ if (terminalIndices.tlen() > 1) {
107
+ test::throwError("Multiple terminal actions");
108
+ }
109
+
110
+ ;; Check that the storage after running the handler matches the expected storage
111
+ int wrongField = compareObjectFields(getContractStorage(), $expectedStorage);
112
+ if (wrongField == INVALID_CLASS_MEMBER) {
113
+ return (
114
+ TEST_FAILED,
115
+ "Storage and expected storage not of the same type"
116
+ );
117
+ } elseif (wrongField != -1) {
118
+ return (
119
+ TEST_FAILED,
120
+ "malformed field ".str::concatInt(wrongField)
121
+ );
122
+ }
123
+ if (expectedTxnContext.tlen() != txnContext.tlen()) {
124
+ return (TEST_FAILED, "malformed txn context");
125
+ }
126
+ ;; check context
127
+ int index = 0;
128
+ while (index < txnContext.tlen()) {
129
+ int mismatch = false;
130
+ if (txnContext.at(index).is_int()) {
131
+ mismatch = (txnContext.int_at(index) != expectedTxnContext.int_at(index));
132
+ } elseif (txnContext.at(index).is_cell()) {
133
+ mismatch = (txnContext.cell_at(index).cell_hash() != expectedTxnContext.cell_at(index).cell_hash());
134
+ } elseif (txnContext.at(index).is_slice()) {
135
+ mismatch = (~ txnContext.slice_at(index).equal_slices(expectedTxnContext.slice_at(index)));
136
+ } else {
137
+ mismatch = (~ txnContext.cell_at(index).cl::hash() == expectedTxnContext.cell_at(index).cl::hash());
138
+ }
139
+ if (mismatch) {
140
+ return (TEST_FAILED, "txn context mismatch at index".str::concatInt(index));
141
+ }
142
+ index += 1;
143
+ }
144
+
145
+ ;; If all checks pass, return success
146
+ return (TEST_SUCCESS, "");
147
+ }
148
+
149
+ (int, slice) test::handler::shouldFail((cell -> tuple) fn, cell $md, int expected_error) impure {
150
+ int failed = false;
151
+ try {
152
+ if (fn($md).tlen() >= 0) {
153
+ failed = true;
154
+ return (TEST_FAILED, "test::handler::shouldFail never throws");
155
+ }
156
+ } catch(x, n) {
157
+ if (n != expected_error) {
158
+ return (
159
+ TEST_FAILED,
160
+ "actual error: "
161
+ .str::concatInt(n)
162
+ .str::concat(" != expected: ")
163
+ .str::concatInt(expected_error)
164
+ );
165
+ }
166
+ }
167
+
168
+ return (TEST_SUCCESS, "");
169
+ }
170
+
171
+ (int, slice) test::permissions::shouldPass(int op, cell $md) impure {
172
+ int failed = false;
173
+ try {
174
+ _callCheckPermissions(op, $md);
175
+ } catch(x, n) {
176
+ failed = true;
177
+ }
178
+ return failed ? (TEST_FAILED, "permissions check should not have thrown") : (TEST_SUCCESS, "");
179
+ }
180
+
181
+ (int, slice) test::permissions::shouldFail(int op, cell $md) impure {
182
+ int failed = false;
183
+ try {
184
+ _callCheckPermissions(op, $md);
185
+ failed = true;
186
+ } catch(x, n) {
187
+ ;; Catch is a function that executes in its own context
188
+ ;; so if you try to return here, it will actually
189
+ ;; return execution to the try block, not the caller of test::permissions::shouldFail
190
+ }
191
+ return failed ? (TEST_FAILED, "permissions check should have thrown") : (TEST_SUCCESS, "");
192
+ }
@@ -0,0 +1,135 @@
1
+ #include "../src/funC++/classlib.fc";
2
+ #include "../src/funC++/txnContext.fc";
3
+ #include "../src/funC++/utils.fc";
4
+
5
+ global slice base_error_msg;
6
+ ;; const int do_profile = -1; ;; doesn't compile with true
7
+ const int do_profile = 0; ;; doesn't compile with false
8
+
9
+ const int TEST_SUCCESS = -1;
10
+ const int TEST_FAILED = 0;
11
+
12
+ const int TEST_FN_IDX = 0;
13
+ const int TEST_NAME_IDX = 1;
14
+
15
+ ;;; ===============================INTERFACE FUNCTIONS===========================
16
+ slice _testName();
17
+ tuple baseTest::getTests() impure;
18
+ cell baseTest::prepare(tuple testCase) impure inline;
19
+
20
+ ;;; ===============================HELPER FUNCTIONS===========================
21
+ const int DONE = 1;
22
+ () emitDone() impure inline {
23
+ var msg = begin_cell()
24
+ .store_uint (12, 4) ;; ext_out_msg_info$11 src:MsgAddressInt ()
25
+ .store_uint (1, 2)
26
+ .store_uint (256, 9)
27
+ .store_uint(DONE, 256)
28
+ .store_uint(0, 64 + 32 + 2) ;; created_lt, created_at, init:Maybe, body:Either
29
+ .end_cell();
30
+ send_raw_message(msg, 0);
31
+ }
32
+
33
+ () test::throwError(slice msg) impure {
34
+ ~strdump(_testName()
35
+ .str::concat(": ")
36
+ .str::concat(base_error_msg)
37
+ .str::concat(": ")
38
+ .str::concat(msg)
39
+ );
40
+ throwError(
41
+ _testName()
42
+ .str::concat(": ")
43
+ .str::concat(base_error_msg)
44
+ .str::concat(": ")
45
+ .str::concat(msg)
46
+ );
47
+ }
48
+
49
+ () test::throwErrorUnless(int condition, slice msg) impure {
50
+ ifnot (condition) {
51
+ test::throwError(msg);
52
+ }
53
+ }
54
+
55
+ slice get_test_name(int index) impure method_id {
56
+ tuple tests = baseTest::getTests();
57
+ tuple testCase = tests.at(index);
58
+ return testCase.slice_at(TEST_NAME_IDX);
59
+ }
60
+
61
+ ;;; ===============================Txn Context Manipulation===========================
62
+
63
+ () setCaller(int caller) impure inline {
64
+ txnContext~tset(_CALLER, caller);
65
+ }
66
+
67
+ () setContractBalance(int balance) impure inline {
68
+ txnContext~tset(_BALANCE, balance);
69
+ }
70
+
71
+ ;;; Returns the current value of `c7`.
72
+ tuple _get_c7() impure asm "c7 PUSH";
73
+
74
+ ;;; Updates the current value of `c7`.
75
+ () _set_c7(tuple c) impure asm "c7 POP";
76
+
77
+ ;; *Testing function only. Do not use in production code!*
78
+ () setNewTime(int newTime) impure {
79
+ tuple c7 = _get_c7();
80
+ _set_c7(
81
+ c7.tset(0,
82
+ c7.tuple_at(0)
83
+ .tset(3, newTime)
84
+ )
85
+ );
86
+ }
87
+
88
+
89
+ ;;; ===============================MAIN DRIVER FOR ALL TESTS===========================
90
+ () main(int myBalance, int msgValue, cell inMsgFull, slice inMsgBody) impure {
91
+ ;; ignore empty messages
92
+ if (inMsgBody.slice_empty?()) {
93
+ return ();
94
+ }
95
+
96
+ initTxnContext(
97
+ myBalance,
98
+ msgValue,
99
+ inMsgFull,
100
+ inMsgBody
101
+ );
102
+
103
+ base_error_msg = "base_error_msg NOT set... ";
104
+
105
+ int index = getOpcode();
106
+
107
+ ;; Allow the test framework to prank arbitrary caller
108
+ setCaller(getOrigin());
109
+
110
+ tuple tests = baseTest::getTests();
111
+ if (index >= tests.tlen()) {
112
+ emitDone();
113
+ } else {
114
+ tuple testCase = tests.at(index);
115
+ var test_fn = testCase.at(TEST_FN_IDX);
116
+ base_error_msg = testCase.at(TEST_NAME_IDX);
117
+ cell input = baseTest::prepare(testCase);
118
+ cell $storage = getContractStorage();
119
+ (int success, slice reason) = test_fn(input);
120
+ setContractStorage($storage);
121
+ test::throwErrorUnless(success == TEST_SUCCESS, reason);
122
+ }
123
+ }
124
+
125
+ (int, slice) test::shouldBeTrue(int condition) {
126
+ ifnot (condition) {
127
+ return (TEST_FAILED, "test::shouldBeTrue");
128
+ } else {
129
+ return (TEST_SUCCESS, "");
130
+ }
131
+ }
132
+
133
+ (int, slice) test::shouldBeFalse(int condition) {
134
+ return test::shouldBeTrue(condition == false);
135
+ }