-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmsg.func
More file actions
537 lines (465 loc) · 19.6 KB
/
msg.func
File metadata and controls
537 lines (465 loc) · 19.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
{-
This file is part of stdlib.func.
It is derived from code originally part of the TON Blockchain project.
stdlib.func is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
stdlib.func is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with stdlib.func (see the file LICENSE.LGPL). If not, see
<https://www.gnu.org/licenses/>. You should also have received a copy of
the GNU General Public License (see the file LICENSE.GPL), which is
referenced by the LGPL.
-}
;; █████╗ ██████╗ ██████╗ ██████╗ ███████╗███████╗███████╗
;; ██╔══██╗██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔════╝
;; ███████║██║ ██║██║ ██║██████╔╝█████╗ ███████╗███████╗
;; ██╔══██║██║ ██║██║ ██║██╔══██╗██╔══╝ ╚════██║╚════██║
;; ██║ ██║██████╔╝██████╔╝██║ ██║███████╗███████║███████║
;; ╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝
{-
# Address manipulation primitives
The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme:
```TL-B
addr_none$00 = MsgAddressExt;
addr_extern$01 len:(## 8) external_address:(bits len)
= MsgAddressExt;
anycast_info$_ depth:(#<= 30) { depth >= 1 }
rewrite_pfx:(bits depth) = Anycast;
addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;
addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
_ _:MsgAddressInt = MsgAddress;
_ _:MsgAddressExt = MsgAddress;
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddress dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;
ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;
```
A deserialized `MsgAddress` is represented by a tuple `t` as follows:
- `addr_none` is represented by `t = (0)`,
i.e., a tuple containing exactly one integer equal to zero.
- `addr_extern` is represented by `t = (1, s)`,
where slice `s` contains the field `external_address`. In other words, `
t` is a pair (a tuple consisting of two entries), containing an integer equal to one and slice `s`.
- `addr_std` is represented by `t = (2, u, x, s)`,
where `u` is either a `null` (if `anycast` is absent) or a slice `s'` containing `rewrite_pfx` (if anycast is present).
Next, integer `x` is the `workchain_id`, and slice `s` contains the address.
- `addr_var` is represented by `t = (3, u, x, s)`,
where `u`, `x`, and `s` have the same meaning as for `addr_std`.
-}
const int BASECHAIN = 0;
const int MASTERCHAIN = -1;
const slice addr_none = "2_"s; ;; addr_none$00 = MsgAddressExt;
;;; Loads an address from the slice.
;;;
;;; Args:
;;; s (slice): Source slice to load the address from.
;;;
;;; Returns:
;;; slice: Extracted address.
;;; slice: Remainder of the source slice.
(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR";
;;; Skips address in the slice.
;;;
;;; Args:
;;; s (slice): Source slice to skip the address in.
;;;
;;; Returns:
;;; slice: Remainder of the source slice after skipping the address.
(slice, ()) ~skip_msg_addr(slice s) asm "LDMSGADDR NIP";
;;; Parses address into tuple with its components.
;;;
;;; Args:
;;; s (slice): Slice containing a valid address.
;;;
;;; Returns:
;;; tuple: Components of the address according to its type (addr_none, addr_extern, addr_std, or addr_var).
tuple parse_addr(slice s) asm "PARSEMSGADDR";
;;; Parses standard address and applies anycast rewriting.
;;;
;;; Args:
;;; s (slice): Slice containing a valid standard address.
;;;
;;; Returns:
;;; int: Workchain ID.
;;; int: 256-bit address as integer.
(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR";
;;; Parses variable-length address and applies anycast rewriting.
;;;
;;; Args:
;;; s (slice): Slice containing a valid address.
;;;
;;; Returns:
;;; int: Workchain ID.
;;; slice: Address data after rewriting.
(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR";
;;; Stores addr_none construction to builder.
;;;
;;; Args:
;;; b (builder): Builder to store addr_none to.
;;;
;;; Returns:
;;; builder: Builder with addr_none appended.
builder store_addr_none(builder b) asm "b{00} STSLICECONST";
(builder, ()) ~store_addr_none(builder b) asm "b{00} STSLICECONST";
;;; Checks if slice contains addr_none construction.
;;;
;;; Args:
;;; s (slice): Slice to check.
;;;
;;; Returns:
;;; int: -1 if slice is addr_none, 0 otherwise.
int addr_none?(slice s) asm "b{00} PUSHSLICE SDEQ";
;;; Checks if address is a standard basechain address without anycast.
;;;
;;; Args:
;;; addr (slice): Slice with address (after load_msg_addr).
;;;
;;; Returns:
;;; int: -1 if valid basechain address, 0 otherwise.
int validate_addr_bc(slice addr) asm "b{10000000000} PUSHSLICE SDPPFXREV";
;;; Checks if address is a standard masterchain address without anycast.
;;;
;;; Args:
;;; addr (slice): Slice with address (after load_msg_addr).
;;;
;;; Returns:
;;; int: -1 if valid masterchain address, 0 otherwise.
int validate_addr_mc(slice addr) asm "b{10011111111} PUSHSLICE SDPPFXREV";
;;; Stores standard basechain address to builder.
;;;
;;; Args:
;;; b (builder): Builder to store the address to.
;;; hash (int): 256-bit address hash.
;;;
;;; Returns:
;;; builder: Builder with basechain address appended.
builder store_bc_address(builder b, int hash) asm(hash b) "b{10000000000} STSLICECONST 256 STU";
(builder, ()) ~store_bc_address(builder b, int hash) asm(hash b) "b{10000000000} STSLICECONST 256 STU";
;;; Stores standard masterchain address to builder.
;;;
;;; Args:
;;; b (builder): Builder to store the address to.
;;; hash (int): 256-bit address hash.
;;;
;;; Returns:
;;; builder: Builder with masterchain address appended.
builder store_mc_address(builder b, int hash) asm(hash b) "b{10011111111} STSLICECONST 256 STU";
(builder, ()) ~store_mc_address(builder b, int hash) asm(hash b) "b{10011111111} STSLICECONST 256 STU";
;;; Validates if slice contains a standard basechain address without anycast.
;;;
;;; Args:
;;; addr (slice): Any slice to validate.
;;;
;;; Returns:
;;; int: -1 if valid basechain address, 0 otherwise.
int ext_validate_addr_bc(slice addr) asm """
DUP
b{10000000000} PUSHSLICE SDPPFXREV SWAP
267 INT 0 INT SCHKBITREFSQ
AND
""";
;;; Validates if slice contains a standard masterchain address without anycast.
;;;
;;; Args:
;;; addr (slice): Any slice to validate.
;;;
;;; Returns:
;;; int: -1 if valid masterchain address, 0 otherwise.
int ext_validate_addr_mc(slice addr) asm """
DUP
b{10011111111} PUSHSLICE SDPPFXREV SWAP
267 INT 0 INT SCHKBITREFSQ
AND
""";
;;; Checks if two addresses have the same workchain.
;;;
;;; Args:
;;; addr1 (slice): First address to compare.
;;; addr2 (slice): Second address to compare.
;;;
;;; Returns:
;;; int: -1 if addresses have the same workchain, 0 otherwise.
int workchains_equal?(slice addr1, slice addr2) asm "REWRITESTDADDR DROP SWAP REWRITESTDADDR DROP EQUAL";
;;; Checks if address has the specified workchain.
;;;
;;; Args:
;;; addr (slice): Address to check.
;;; wc (int): Workchain ID to match.
;;;
;;; Returns:
;;; int: -1 if address has the specified workchain, 0 otherwise.
int workchain_match?(slice addr, int wc) asm(wc addr) "REWRITESTDADDR DROP EQUAL";
;;; Checks if address belongs to the basechain (workchain 0).
;;;
;;; Args:
;;; addr (slice): Address to check.
;;;
;;; Returns:
;;; int: -1 if address is in basechain, 0 otherwise.
int basechain_addr?(slice addr) asm "REWRITESTDADDR DROP 0 EQINT";
;;; Checks if address belongs to the masterchain (workchain -1).
;;;
;;; Args:
;;; addr (slice): Address to check.
;;;
;;; Returns:
;;; int: -1 if address is in masterchain, 0 otherwise.
int masterchain_addr?(slice addr) asm "REWRITESTDADDR DROP -1 EQINT";
;;; Stores StateInit to builder.
;;;
;;; Args:
;;; b (builder): Builder to store StateInit to.
;;; data (cell): Contract data.
;;; code (cell): Contract code.
;;;
;;; Returns:
;;; builder: Builder with StateInit appended.
builder store_state_init(builder b, cell data, cell code) asm(data code b) "b{00110} STSLICECONST STREF STREF";
(builder, ()) ~store_state_init(builder b, cell data, cell code) asm(data code b) "b{00110} STSLICECONST STREF STREF";
;; ███╗ ███╗███████╗███████╗███████╗ █████╗ ██████╗ ███████╗███████╗
;; ████╗ ████║██╔════╝██╔════╝██╔════╝██╔══██╗██╔════╝ ██╔════╝██╔════╝
;; ██╔████╔██║█████╗ ███████╗███████╗███████║██║ ███╗█████╗ ███████╗
;; ██║╚██╔╝██║██╔══╝ ╚════██║╚════██║██╔══██║██║ ██║██╔══╝ ╚════██║
;; ██║ ╚═╝ ██║███████╗███████║███████║██║ ██║╚██████╔╝███████╗███████║
;; ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝
;; ===== MSG FLAGS =====
const slice BOUNCEABLE = "62_"s; ;; 0b011000 tag - 0, ihr_disabled - 1, bounce - 1, bounced - 0, src = adr_none$00
const slice NON_BOUNCEABLE = "42_"s; ;; 0b010000 tag - 0, ihr_disabled - 1, bounce - 0, bounced - 0, src = adr_none$00
;;; Stores message flags to builder.
;;;
;;; Args:
;;; b (builder): Builder to store flags to.
;;; flag (int): Flag value to store.
;;;
;;; Returns:
;;; builder: Builder with flags appended.
builder store_msg_flags(builder b, int flag) asm(flag b) "6 STU";
(builder, ()) ~store_msg_flags(builder b, int flag) asm(flag b) "6 STU";
;;; Stores bounceable message flags to builder.
;;;
;;; Args:
;;; b (builder): Builder to store flags to.
;;;
;;; Returns:
;;; builder: Builder with bounceable flags appended.
builder store_msg_flags_bounceable(builder b) asm "b{011000} STSLICECONST";
(builder, ()) ~store_msg_flags_bounceable(builder b) asm "b{011000} STSLICECONST";
;;; Stores non-bounceable message flags to builder.
;;;
;;; Args:
;;; b (builder): Builder to store flags to.
;;;
;;; Returns:
;;; builder: Builder with non-bounceable flags appended.
builder store_msg_flags_non_bounceable(builder b) asm "b{010000} STSLICECONST";
(builder, ()) ~store_msg_flags_non_bounceable(builder b) asm "b{010000} STSLICECONST";
;;; Loads message flags from slice.
;;;
;;; Args:
;;; s (slice): Slice to load flags from.
;;;
;;; Returns:
;;; slice: Remainder of the slice.
;;; int: Loaded flags value.
(slice, int) load_msg_flags(slice s) asm(-> 1 0) "4 LDU";
;;; Parses full message cell into components.
;;;
;;; Args:
;;; full_message (cell): Cell containing a full message.
;;;
;;; Returns:
;;; int: Message flags.
;;; slice: Sender address.
;;; int: Forward fee.
(int, slice, int) parse_message(cell full_message) asm "CTOS 4 LDU LDMSGADDR LDMSGADDR LDGRAMS SKIPDICT LDGRAMS LDGRAMS DROP 3 1 BLKDROP2";
;;; Checks if message is bounceable.
;;;
;;; Args:
;;; flags (int): Message flags.
;;;
;;; Returns:
;;; int: -1 if message is bounceable, 0 otherwise.
int bounceable?(int flags) asm "2 INT AND";
;;; Checks if message is bounced.
;;;
;;; Args:
;;; flags (int): Message flags.
;;;
;;; Returns:
;;; int: -1 if message is bounced, 0 otherwise.
int bounced?(int flags) asm "ONE AND";
;;; Skips bounced prefix in slice.
;;; Throws an exception if the slice doesn't begin with the bounced prefix (0xFFFFFFFF).
;;;
;;; Args:
;;; s (slice): Source slice.
;;;
;;; Returns:
;;; slice: Remainder of the slice after skipping the bounced prefix.
slice skip_bounced_prefix(slice s) asm "x{FFFFFFFF} SDBEGINS";
(slice, ()) ~skip_bounced_prefix(slice s) asm "x{FFFFFFFF} SDBEGINS";
;; ===== MSG BODY =====
;;; Stores operation code to builder.
;;;
;;; Args:
;;; b (builder): Builder to store operation code to.
;;; op (int): 32-bit operation code.
;;;
;;; Returns:
;;; builder: Builder with operation code appended.
builder store_op(builder b, int op) asm(op b) "32 STU";
(builder, ()) ~store_op(builder b, int op) asm(op b) "32 STU";
;;; Stores query ID to builder.
;;;
;;; Args:
;;; b (builder): Builder to store query ID to.
;;; query_id (int): 64-bit query ID.
;;;
;;; Returns:
;;; builder: Builder with query ID appended.
builder store_query_id(builder b, int query_id) asm(query_id b) "64 STU";
(builder, ()) ~store_query_id(builder b, int query_id) asm(query_id b) "64 STU";
;;; Loads operation code from slice.
;;;
;;; Args:
;;; s (slice): Source slice.
;;;
;;; Returns:
;;; slice: Remainder of the slice.
;;; int: 32-bit operation code.
(slice, int) load_op(slice s) asm(-> 1 0) "32 LDU";
;;; Loads query ID from slice.
;;;
;;; Args:
;;; s (slice): Source slice.
;;;
;;; Returns:
;;; slice: Remainder of the slice.
;;; int: 64-bit query ID.
(slice, int) load_query_id(slice s) asm(-> 1 0) "64 LDU";
;;; Loads operation code and query ID from slice.
;;;
;;; Args:
;;; s (slice): Source slice.
;;;
;;; Returns:
;;; slice: Remainder of the slice.
;;; int: 32-bit operation code.
;;; int: 64-bit query ID.
(slice, int, int) load_op_and_query_id(slice s) asm(-> 2 0 1) "32 LDU 64 LDU";
(slice, (int, int)) ~load_op_and_query_id(slice s) asm(-> 2 0 1) "32 LDU 64 LDU";
;;; Skips operation code in slice.
;;;
;;; Args:
;;; s (slice): Source slice.
;;;
;;; Returns:
;;; slice: Remainder of the slice after skipping the operation code.
slice skip_op(slice s) asm "32 LDU NIP";
(slice, ()) ~skip_op(slice s) asm "32 LDU NIP";
;;; Skips query ID in slice.
;;;
;;; Args:
;;; s (slice): Source slice.
;;;
;;; Returns:
;;; slice: Remainder of the slice after skipping the query ID.
slice skip_query_id(slice s) asm "64 LDU NIP";
(slice, ()) ~skip_query_id(slice s) asm "64 LDU NIP";
;; ===== SEND =====
const int MSG_INFO_REST_BITS = 1 + 4 + 4 + 64 + 32;
;; https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L155
;; message$_ {X:Type} info:CommonMsgInfo
;; Maybe (Either StateInit ^StateInit)
;; body:(Either X ^X) = Message X;
;;
;;message$_ {X:Type} info:CommonMsgInfoRelaxed
;; init:(Maybe (Either StateInit ^StateInit))
;; body:(Either X ^X) = MessageRelaxed X;
;;
;;_ (Message Any) = MessageAny;
;; if have StateInit (always place StateInit in ref):
;; 0b11 for `Maybe (Either StateInit ^StateInit)` and 0b1 or 0b0 for `body:(Either X ^X)`
const int MSG_WITH_STATE_INIT_AND_BODY_SIZE = MSG_INFO_REST_BITS + 1 + 1 + 1;
const int MSG_HAVE_STATE_INIT = 4;
const int MSG_STATE_INIT_IN_REF = 2;
const int MSG_BODY_IN_REF = 1;
;; if no StateInit:
;; 0b0 for `Maybe (Either StateInit ^StateInit)` and 0b1 or 0b0 for `body:(Either X ^X)`
const int MSG_ONLY_BODY_SIZE = MSG_INFO_REST_BITS + 1 + 1;
;; ===== SEND MODES =====
;; For `send_raw_message` and `send_message`:
;;; x = 0 is used for ordinary messages; the gas fees are deducted from the senging amount; action phaes should NOT be ignored.
const int sendmode::REGULAR = 0;
;;; +1 means that the sender wants to pay transfer fees separately.
const int sendmode::PAY_FEES_SEPARATELY = 1;
;;; + 2 means that any errors arising while processing this message during the action phase should be ignored.
const int sendmode::IGNORE_ERRORS = 2;
;;; + 32 means that the current account must be destroyed if its resulting balance is zero.
const int sendmode::DESTROY = 32;
;;; x = 64 is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message.
const int sendmode::CARRY_ALL_REMAINING_MESSAGE_VALUE = 64;
;;; x = 128 is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message).
const int sendmode::CARRY_ALL_BALANCE = 128;
;;; in the case of action fail - bounce transaction. No effect if sendmode::IGNORE_ERRORS (+2) is used. TVM UPGRADE 2023-07.
const int sendmode::BOUNCE_ON_ACTION_FAIL = 16;
;; Only for `send_message`:
;;; do not create an action, only estimate fee
const int sendmode::ESTIMATE_FEE_ONLY = 1024;
;; Other modes affect the fee calculation as follows:
;; +64 substitutes the entire balance of the incoming message as an outcoming value (slightly inaccurate, gas expenses that cannot be estimated before the computation is completed are not taken into account).
;; +128 substitutes the value of the entire balance of the contract before the start of the computation phase (slightly inaccurate, since gas expenses that cannot be estimated before the completion of the computation phase are not taken into account).
;; ===== RESERVE MODES =====
;;; Creates an output action which would reserve exactly x nanograms (if y = 0).
const int reserve::REGULAR = 0;
;;; Creates an output action which would reserve at most x nanograms (if y = 2).
;;; Bit +2 in y means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved.
const int reserve::AT_MOST = 2;
;;; in the case of action fail - bounce transaction. No effect if RESERVE_AT_MOST (+2) is used. TVM UPGRADE 2023-07.
const int reserve::BOUNCE_ON_ACTION_FAIL = 16;
;;; Creates an output action which would reserve specified amount of nanocoins from the balance.
;;;
;;; Args:
;;; amount (int): Amount of nanocoins to reserve.
;;; mode (int): Reservation mode flags.
;;;
;;; Returns:
;;; None.
() raw_reserve(int amount, int mode) impure asm "RAWRESERVE";
;;; Creates an output action which would reserve specified amount of nanocoins and other currencies from the balance.
;;;
;;; Args:
;;; amount (int): Amount of nanocoins to reserve.
;;; extra_amount (cell): Dictionary with extra currencies to reserve or null.
;;; mode (int): Reservation mode flags.
;;;
;;; Returns:
;;; None.
() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX";
;;; Creates an output action which would send a raw message.
;;;
;;; Args:
;;; msg (cell): Message cell to send.
;;; mode (int): Sending mode flags.
;;;
;;; Returns:
;;; None.
() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG";
;;; Creates an output action and returns a fee for creating a message.
;;;
;;; Args:
;;; msg (cell): Message cell to send.
;;; mode (int): Sending mode flags.
;;;
;;; Returns:
;;; int: Estimated fee for creating the message.
int send_message(cell msg, int mode) impure asm "SENDMSG";