{"code":"b5ee9c7201021c01000701000114ff00f4a413f4bcf2c80b0102016202030202cb0405020120161701f7d007434c0c05c6c239144d7c0e00835c874c7c0608405e351466ea44c38601035c87e800c3b51343e803e903e903e903535345415a841440d104c321401be80940133c59633c58073c5b333327b55383e903e900c7e800c7d007e800c7e80004c5c3e0e80b4c7c04074cfc044bb51343e803e903e903e9035353449e06001da23864658380e78b64814183fa0bc004fc8210642b7d07ba8ed3363639395350c7055168c70516b1f2e04b03fa4021fa4430c000f2e14dfa00d4d120d0d31f018210178d4519baf2e0488040d721fa00fa4031fa4031fa0020d70b009ad74bc00101c001b0f2b19130e254431ae0278210178d4519ba8e8910675f07334434db3ce03b3b2582107bdd97debae302250708090a018e2191729171e2f839206e938124b89120e2216e94318128739101e25023a813a0738103a370f83ca00270f83612a00170f836a07381040982100966018070f837a0bcf2b024597f0b03dced44d0fa00fa40fa40fa40d4d4d10afa005161a106fa40fa40f82854636170546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c9f9007074c8cb02ca07cbffc9d0500dc705f2e04a0bfa0021925f04e30d28d70b01c000b3971038102735355be30d050c0d0e01d2353704fa00fa40f82854120b70546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c9f9007074c8cb02ca07cbffc9d05007c705f2e04aa10503045076c85006fa025004cf1658cf1601cf16ccccc9ed54fa40d120d70b01c000b3915be30d0f03f482102c76b973bae302342482106501f354ba8e263033355131c705f2e04901fa40d103505504c85006fa025004cf1658cf1601cf16ccccc9ed54e0248210fb88e119ba8e2731333502d15122c705f2e0498b021035443302c85006fa025004cf1658cf1601cf16ccccc9ed54e038238210235caf52bae302362210111200f482103b9aca0070fb02f828450470546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c920f9007074c8cb02ca07cbffc9d0c8801801cb0501cf1658fa02029858775003cb6bcccc9730017158cb6acce2c98011fb005024a0441503c85006fa025004cf1658cf1601cf16ccccc9ed540060c882107362d09c01cb1f2a01cb3f5004fa0258cf1658cf16c9c8801001cb0524cf1658fa02017158cb6accc98011fb00005e5076a18010fb02c8801001cb055007cf1670fa027001cb6a8210d53276db01cb1f500301cb3fc9810082fb001443300028c85006fa025004cf1658cf1601cf16ccccc9ed540044c8801001cb0501cf1670fa027001cb6a8210d53276db01cb1f0101cb3fc98042fb0001fc10455f05333302fa40d2000101d195c821cf16c9916de2c8801001cb055004cf1670fa027001cb6a8210d173540001cb1f5801cb3f21fa4430c0008e35f828500470546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c9f9007074c8cb02ca07cbffc9d012cf1697316c127001cb01e2f400c91302ec375f0303c705f2e04901fa40fa00d4d120d0d31f01018040d7212182100f8a7ea5ba8e4d35208210595f07bcba8e2c3003fa0031fa4031f401d120f839206e943081180fde718102f270f8380170f836a0811ba470f836a0bcf2b08e138210eed236d3ba9503d30331d19433f2c048e2e2e30d430370141500b28210cb862902ba8e24325134c705f2e049c858cf16c9151034c85006fa025004cf1658cf1601cf16ccccc9ed54e05b34342282102508d66aba9e32c705f2e049d4d4d101ed54fb04e010235f038210d372158cbadc840ff2f000088050fb0000ce31fa0031fa4031fa4031f401fa0020d70b009ad74bc00101c001b0f2b19130e25442152191729171e2f839206e938124b89120e2216e94318128739101e25023a813a0738103a370f83ca00270f83612a00170f836a07381040982100966018070f837a0bcf2b000c082103b9aca0070fb02f828450470546004131503c8cb0358fa0201cf1601cf16c921c8cb0113f40012f400cb00c920f9007074c8cb02ca07cbffc9d0c8801801cb0501cf1658fa02029858775003cb6bcccc9730017158cb6acce2c98011fb000029bd9adf6a2687d007d207d207d206a6a68881aaf82c02014818190201581a1b0021b7849da89a1f401f481f481f481a9a9a300089adbcf6a2687d007d207d207d206a6a688aaf82fc1400b82a3002098a81e46581ac7d0100e78b00e78b6490e4658089fa00097a00658064fc80383a6465816503e5ffe4e84000d7af16f6a2687d007d207d207d206a6a68b6113f80e836c1783872ebdb514d9c97c283b7f0ae5179029e2b6119c39462719e4f46ed8f7413e62c780a417877407e978f01a40711411b1acb773a96bdd93fa83bb5ca8435013c8c4b3ac91f4589b4780a38646583fa0064a181c0","code_hash":"a9bfedc76d60b332e8019e405505aadf4d7f870b8d3bae7abcfeb868681e6b2a","methods":[{"id":78683,"method":"get_next_admin_address"},{"id":103289,"method":"get_wallet_address"},{"id":106029,"method":"get_jetton_data"}],"compiler":"func","source":{"files":[{"name":"contracts/imports/stdlib_modern.fc","content":";; Standard library for funC\n;;\n\n{-\n    This file is part of TON FunC Standard Library.\n\n    FunC Standard Library is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Lesser General Public License as published by\n    the Free Software Foundation, either version 2 of the License, or\n    (at your option) any later version.\n\n    FunC Standard Library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Lesser General Public License for more details.\n\n-}\n\n{-\n  # Tuple manipulation primitives\n  The names and the types are mostly self-explaining.\n  See [polymorhism with forall](https://ton.org/docs/#/func/functions?id=polymorphism-with-forall)\n  for more info on the polymorphic functions.\n\n  Note that currently values of atomic type `tuple` can't be cast to composite tuple type (e.g. `[int, cell]`)\n  and vise versa.\n-}\n\n{-\n  # Lisp-style lists\n\n  Lists can be represented as nested 2-elements tuples.\n  Empty list is conventionally represented as TVM `null` value (it can be obtained by calling [null()]).\n  For example, tuple `(1, (2, (3, null)))` represents list `[1, 2, 3]`. Elements of a list can be of different types.\n-}\n\n;;; Adds an element to the beginning of lisp-style list.\nforall X -> tuple cons(X head, tuple tail) asm \"CONS\";\n\n;;; Extracts the head and the tail of lisp-style list.\nforall X -> (X, tuple) uncons(tuple list) asm \"UNCONS\";\n\n;;; Extracts the tail and the head of lisp-style list.\nforall X -> (tuple, X) list_next(tuple list) asm(-> 1 0) \"UNCONS\";\n\n;;; Returns the head of lisp-style list.\nforall X -> X car(tuple list) asm \"CAR\";\n\n;;; Returns the tail of lisp-style list.\ntuple cdr(tuple list) asm \"CDR\";\n\n;;; Creates tuple with zero elements.\ntuple empty_tuple() asm \"NIL\";\n\n;;; Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)`\n;;; is of length at most 255. Otherwise throws a type check exception.\nforall X -> tuple tpush(tuple t, X value) asm \"TPUSH\";\nforall X -> (tuple, ()) ~tpush(tuple t, X value) asm \"TPUSH\";\n\n;;; Creates a tuple of length one with given argument as element.\nforall X -> [X] single(X x) asm \"SINGLE\";\n\n;;; Unpacks a tuple of length one\nforall X -> X unsingle([X] t) asm \"UNSINGLE\";\n\n;;; Creates a tuple of length two with given arguments as elements.\nforall X, Y -> [X, Y] pair(X x, Y y) asm \"PAIR\";\n\n;;; Unpacks a tuple of length two\nforall X, Y -> (X, Y) unpair([X, Y] t) asm \"UNPAIR\";\n\n;;; Creates a tuple of length three with given arguments as elements.\nforall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm \"TRIPLE\";\n\n;;; Unpacks a tuple of length three\nforall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm \"UNTRIPLE\";\n\n;;; Creates a tuple of length four with given arguments as elements.\nforall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm \"4 TUPLE\";\n\n;;; Unpacks a tuple of length four\nforall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm \"4 UNTUPLE\";\n\n;;; Returns the first element of a tuple (with unknown element types).\nforall X -> X first(tuple t) asm \"FIRST\";\n\n;;; Returns the second element of a tuple (with unknown element types).\nforall X -> X second(tuple t) asm \"SECOND\";\n\n;;; Returns the third element of a tuple (with unknown element types).\nforall X -> X third(tuple t) asm \"THIRD\";\n\n;;; Returns the fourth element of a tuple (with unknown element types).\nforall X -> X fourth(tuple t) asm \"3 INDEX\";\n\n;;; Returns the first element of a pair tuple.\nforall X, Y -> X pair_first([X, Y] p) asm \"FIRST\";\n\n;;; Returns the second element of a pair tuple.\nforall X, Y -> Y pair_second([X, Y] p) asm \"SECOND\";\n\n;;; Returns the first element of a triple tuple.\nforall X, Y, Z -> X triple_first([X, Y, Z] p) asm \"FIRST\";\n\n;;; Returns the second element of a triple tuple.\nforall X, Y, Z -> Y triple_second([X, Y, Z] p) asm \"SECOND\";\n\n;;; Returns the third element of a triple tuple.\nforall X, Y, Z -> Z triple_third([X, Y, Z] p) asm \"THIRD\";\n\n\n;;; Push null element (casted to given type)\n;;; By the TVM type `Null` FunC represents absence of a value of some atomic type.\n;;; So `null` can actually have any atomic type.\nforall X -> X null() asm \"PUSHNULL\";\n\n;;; Moves a variable [x] to the top of the stack\nforall X -> (X, ()) ~impure_touch(X x) impure asm \"NOP\";\n\n\n\n;;; Returns the current Unix time as an Integer\nint now() asm \"NOW\";\n\n;;; Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`.\n;;; If necessary, it can be parsed further using primitives such as [parse_std_addr].\nslice my_address() asm \"MYADDR\";\n\n;;; Returns the balance of the smart contract as a tuple consisting of an int\n;;; (balance in nanotoncoins) and a `cell`\n;;; (a dictionary with 32-bit keys representing the balance of \"extra currencies\")\n;;; at the start of Computation Phase.\n;;; Note that RAW primitives such as [send_raw_message] do not update this field.\n[int, cell] get_balance() asm \"BALANCE\";\n\n;;; Returns the logical time of the current transaction.\nint cur_lt() asm \"LTIME\";\n\n;;; Returns the starting logical time of the current block.\nint block_lt() asm \"BLOCKLT\";\n\n;;; Computes the representation hash of a `cell` [c] and returns it as a 256-bit unsigned integer `x`.\n;;; Useful for signing and checking signatures of arbitrary entities represented by a tree of cells.\nint cell_hash(cell c) asm \"HASHCU\";\n\n;;; Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`.\n;;; The result is the same as if an ordinary cell containing only data and references from `s` had been created\n;;; and its hash computed by [cell_hash].\nint slice_hash(slice s) asm \"HASHSU\";\n\n;;; Computes sha256 of the data bits of `slice` [s]. If the bit length of `s` is not divisible by eight,\n;;; throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`.\nint string_hash(slice s) asm \"SHA256U\";\n\n{-\n  # Signature checks\n-}\n\n;;; Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data)\n;;; using [public_key] (also represented by a 256-bit unsigned integer).\n;;; The signature must contain at least 512 data bits; only the first 512 bits are used.\n;;; The result is `−1` if the signature is valid, `0` otherwise.\n;;; Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`.\n;;; That is, if [hash] is computed as the hash of some data, these data are hashed twice,\n;;; the second hashing occurring inside `CHKSIGNS`.\nint check_signature(int hash, slice signature, int public_key) asm \"CHKSIGNU\";\n\n;;; Checks whether [signature] is a valid Ed25519-signature of the data portion of `slice data` using `public_key`,\n;;; similarly to [check_signature].\n;;; If the bit length of [data] is not divisible by eight, throws a cell underflow exception.\n;;; The verification of Ed25519 signatures is the standard one,\n;;; with sha256 used to reduce [data] to the 256-bit number that is actually signed.\nint check_data_signature(slice data, slice signature, int public_key) asm \"CHKSIGNS\";\n\n{---\n  # Computation of boc size\n  The primitives below may be useful for computing storage fees of user-provided data.\n-}\n\n;;; Returns `(x, y, z, -1)` or `(null, null, null, 0)`.\n;;; Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z`\n;;; in the DAG rooted at `cell` [c], effectively returning the total storage used by this DAG taking into account\n;;; the identification of equal cells.\n;;; The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG,\n;;; with a hash table of visited cell hashes used to prevent visits of already-visited cells.\n;;; The total count of visited cells `x` cannot exceed non-negative [max_cells];\n;;; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and\n;;; a zero flag is returned to indicate failure. If [c] is `null`, returns `x = y = z = 0`.\n(int, int, int) compute_data_size(cell c, int max_cells) impure asm \"CDATASIZE\";\n\n;;; Similar to [compute_data_size?], but accepting a `slice` [s] instead of a `cell`.\n;;; The returned value of `x` does not take into account the cell that contains the `slice` [s] itself;\n;;; however, the data bits and the cell references of [s] are accounted for in `y` and `z`.\n(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm \"SDATASIZE\";\n\n;;; A non-quiet version of [compute_data_size?] that throws a cell overflow exception (`8`) on failure.\n(int, int, int, int) compute_data_size?(cell c, int max_cells) asm \"CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT\";\n\n;;; A non-quiet version of [slice_compute_data_size?] that throws a cell overflow exception (8) on failure.\n(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm \"SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT\";\n\n;;; Throws an exception with exit_code excno if cond is not 0 (commented since implemented in compilator)\n;; () throw_if(int excno, int cond) impure asm \"THROWARGIF\";\n\n{--\n  # Debug primitives\n  Only works for local TVM execution with debug level verbosity\n-}\n;;; Dumps the stack (at most the top 255 values) and shows the total stack depth.\n() dump_stack() impure asm \"DUMPSTK\";\n\n{-\n  # Persistent storage save and load\n-}\n\n;;; Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later.\ncell get_data() asm \"c4 PUSH\";\n\n;;; Sets `cell` [c] as persistent contract data. You can update persistent contract storage with this primitive.\n() set_data(cell c) impure asm \"c4 POP\";\n\n{-\n  # Continuation primitives\n-}\n;;; Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls.\n;;; The primitive returns the current value of `c3`.\ncont get_c3() impure asm \"c3 PUSH\";\n\n;;; Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time.\n;;; Note that after execution of this primitive the current code\n;;; (and the stack of recursive function calls) won't change,\n;;; but any other function call will use a function from the new code.\n() set_c3(cont c) impure asm \"c3 POP\";\n\n;;; Transforms a `slice` [s] into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist.\ncont bless(slice s) impure asm \"BLESS\";\n\n{---\n  # Gas related primitives\n-}\n\n;;; Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero,\n;;; decreasing the value of `gr` by `gc` in the process.\n;;; In other words, the current smart contract agrees to buy some gas to finish the current transaction.\n;;; This action is required to process external messages, which bring no value (hence no gas) with themselves.\n;;;\n;;; For more details check [accept_message effects](https://ton.org/docs/#/smart-contracts/accept).\n() accept_message() impure asm \"ACCEPT\";\n\n;;; Sets current gas limit `gl` to the minimum of limit and `gm`, and resets the gas credit `gc` to zero.\n;;; If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`,\n;;; an (unhandled) out of gas exception is thrown before setting new gas limits.\n;;; Notice that [set_gas_limit] with an argument `limit ≥ 2^63 − 1` is equivalent to [accept_message].\n() set_gas_limit(int limit) impure asm \"SETGASLIMIT\";\n\n;;; Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”)\n;;; so that the current execution is considered “successful” with the saved values even if an exception\n;;; in Computation Phase is thrown later.\n() commit() impure asm \"COMMIT\";\n\n;;; Not implemented\n;;; Computes the amount of gas that can be bought for `amount` nanoTONs,\n;;; and sets `gl` accordingly in the same way as [set_gas_limit].\n;;() buy_gas(int amount) impure asm \"BUYGAS\";\n\n;;; Computes the minimum of two integers [x] and [y].\nint min(int x, int y) asm \"MIN\";\n\n;;; Computes the maximum of two integers [x] and [y].\nint max(int x, int y) asm \"MAX\";\n\n;;; Sorts two integers.\n(int, int) minmax(int x, int y) asm \"MINMAX\";\n\n;;; Computes the absolute value of an integer [x].\nint abs(int x) asm \"ABS\";\n\n{-\n  # Slice primitives\n\n  It is said that a primitive _loads_ some data,\n  if it returns the data and the remainder of the slice\n  (so it can also be used as [modifying method](https://ton.org/docs/#/func/statements?id=modifying-methods)).\n\n  It is said that a primitive _preloads_ some data, if it returns only the data\n  (it can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods)).\n\n  Unless otherwise stated, loading and preloading primitives read the data from a prefix of the slice.\n-}\n\n\n;;; Converts a `cell` [c] into a `slice`. Notice that [c] must be either an ordinary cell,\n;;; or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/docs/tvm.pdf), 3.1.2)\n;;; which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards.\nslice begin_parse(cell c) asm \"CTOS\";\n\n;;; Checks if [s] is empty. If not, throws an exception.\n() end_parse(slice s) impure asm \"ENDS\";\n\n;;; Loads the first reference from the slice.\n(slice, cell) load_ref(slice s) asm(-> 1 0) \"LDREF\";\n\n;;; Preloads the first reference from the slice.\ncell preload_ref(slice s) asm \"PLDREF\";\n\n{- Functions below are commented because are implemented on compilator level for optimisation -}\n\n;;; Loads a signed [len]-bit integer from a slice [s].\n;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) \"LDIX\";\n\n;;; Loads an unsigned [len]-bit integer from a slice [s].\n;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) \"LDUX\";\n\n;;; Preloads a signed [len]-bit integer from a slice [s].\n;; int preload_int(slice s, int len) asm \"PLDIX\";\n\n;;; Preloads an unsigned [len]-bit integer from a slice [s].\n;; int preload_uint(slice s, int len) asm \"PLDUX\";\n\n;;; Loads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`.\n;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) \"LDSLICEX\";\n\n;;; Preloads the first `0 ≤ len ≤ 1023` bits from slice [s] into a separate `slice s''`.\n;; slice preload_bits(slice s, int len) asm \"PLDSLICEX\";\n\n;;; Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`).\n(slice, int) load_grams(slice s) asm(-> 1 0) \"LDGRAMS\";\n(slice, int) load_coins(slice s) asm(-> 1 0) \"LDVARUINT16\";\n\n;;; Returns all but the first `0 ≤ len ≤ 1023` bits of `slice` [s].\nslice skip_bits(slice s, int len) asm \"SDSKIPFIRST\";\n(slice, ()) ~skip_bits(slice s, int len) asm \"SDSKIPFIRST\";\n\n;;; Returns the first `0 ≤ len ≤ 1023` bits of `slice` [s].\nslice first_bits(slice s, int len) asm \"SDCUTFIRST\";\n\n;;; Returns all but the last `0 ≤ len ≤ 1023` bits of `slice` [s].\nslice skip_last_bits(slice s, int len) asm \"SDSKIPLAST\";\n(slice, ()) ~skip_last_bits(slice s, int len) asm \"SDSKIPLAST\";\n\n;;; Returns the last `0 ≤ len ≤ 1023` bits of `slice` [s].\nslice slice_last(slice s, int len) asm \"SDCUTLAST\";\n\n;;; Loads a dictionary `D` (HashMapE) from `slice` [s].\n;;; (returns `null` if `nothing` constructor is used).\n(slice, cell) load_dict(slice s) asm(-> 1 0) \"LDDICT\";\n\n;;; Preloads a dictionary `D` from `slice` [s].\ncell preload_dict(slice s) asm \"PLDDICT\";\n\n;;; Loads a dictionary as [load_dict], but returns only the remainder of the slice.\nslice skip_dict(slice s) asm \"SKIPDICT\";\n(slice, ()) ~skip_dict(slice s) asm \"SKIPDICT\";\n\n;;; Loads (Maybe ^Cell) from `slice` [s].\n;;; In other words loads 1 bit and if it is true\n;;; loads first ref and return it with slice remainder\n;;; otherwise returns `null` and slice remainder\n(slice, cell) load_maybe_ref(slice s) asm(-> 1 0) \"LDOPTREF\";\n\n;;; Preloads (Maybe ^Cell) from `slice` [s].\ncell preload_maybe_ref(slice s) asm \"PLDOPTREF\";\n\n\n;;; Returns the depth of `cell` [c].\n;;; If [c] has no references, then return `0`;\n;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [c].\n;;; If [c] is a `null` instead of a cell, returns zero.\nint cell_depth(cell c) asm \"CDEPTH\";\n\n\n{-\n  # Slice size primitives\n-}\n\n;;; Returns the number of references in `slice` [s].\nint slice_refs(slice s) asm \"SREFS\";\n\n;;; Returns the number of data bits in `slice` [s].\nint slice_bits(slice s) asm \"SBITS\";\n\n;;; Returns both the number of data bits and the number of references in `slice` [s].\n(int, int) slice_bits_refs(slice s) asm \"SBITREFS\";\n\n;;; Checks whether a `slice` [s] is empty (i.e., contains no bits of data and no cell references).\nint slice_empty?(slice s) asm \"SEMPTY\";\n\n;;; Checks whether `slice` [s] has no bits of data.\nint slice_data_empty?(slice s) asm \"SDEMPTY\";\n\n;;; Checks whether `slice` [s] has no references.\nint slice_refs_empty?(slice s) asm \"SREMPTY\";\n\n;;; Returns the depth of `slice` [s].\n;;; If [s] has no references, then returns `0`;\n;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [s].\nint slice_depth(slice s) asm \"SDEPTH\";\n\n{-\n  # Builder size primitives\n-}\n\n;;; Returns the number of cell references already stored in `builder` [b]\nint builder_refs(builder b) asm \"BREFS\";\n\n;;; Returns the number of data bits already stored in `builder` [b].\nint builder_bits(builder b) asm \"BBITS\";\n\n;;; Returns the depth of `builder` [b].\n;;; If no cell references are stored in [b], then returns 0;\n;;; otherwise the returned value is one plus the maximum of depths of cells referred to from [b].\nint builder_depth(builder b) asm \"BDEPTH\";\n\n{-\n  # Builder primitives\n  It is said that a primitive _stores_ a value `x` into a builder `b`\n  if it returns a modified version of the builder `b'` with the value `x` stored at the end of it.\n  It can be used as [non-modifying method](https://ton.org/docs/#/func/statements?id=non-modifying-methods).\n\n  All the primitives below first check whether there is enough space in the `builder`,\n  and only then check the range of the value being serialized.\n-}\n\n;;; Creates a new empty `builder`.\nbuilder begin_cell() asm \"NEWC\";\n\n;;; Converts a `builder` into an ordinary `cell`.\ncell end_cell(builder b) asm \"ENDC\";\n\n;;; Stores a reference to `cell` [c] into `builder` [b].\nbuilder store_ref(builder b, cell c) asm(c b) \"STREF\";\n\n;;; Stores an unsigned [len]-bit integer `x` into `b` for `0 ≤ len ≤ 256`.\n;; builder store_uint(builder b, int x, int len) asm(x b len) \"STUX\";\n\n;;; Stores a signed [len]-bit integer `x` into `b` for` 0 ≤ len ≤ 257`.\n;; builder store_int(builder b, int x, int len) asm(x b len) \"STIX\";\n\n\n;;; Stores `slice` [s] into `builder` [b]\nbuilder store_slice(builder b, slice s) asm \"STSLICER\";\n\n;;; Stores (serializes) an integer [x] in the range `0..2^128 − 1` into `builder` [b].\n;;; The serialization of [x] consists of a 4-bit unsigned big-endian integer `l`,\n;;; which is the smallest integer `l ≥ 0`, such that `x < 2^8l`,\n;;; followed by an `8l`-bit unsigned big-endian representation of [x].\n;;; If [x] does not belong to the supported range, a range check exception is thrown.\n;;;\n;;; Store amounts of TonCoins to the builder as VarUInteger 16\nbuilder store_grams(builder b, int x) asm \"STGRAMS\";\nbuilder store_coins(builder b, int x) asm \"STVARUINT16\";\n\n;;; Stores dictionary `D` represented by `cell` [c] or `null` into `builder` [b].\n;;; In other words, stores a `1`-bit and a reference to [c] if [c] is not `null` and `0`-bit otherwise.\nbuilder store_dict(builder b, cell c) asm(c b) \"STDICT\";\n\n;;; Stores (Maybe ^Cell) to builder:\n;;; if cell is null store 1 zero bit\n;;; otherwise store 1 true bit and ref to cell\nbuilder store_maybe_ref(builder b, cell c) asm(c b) \"STOPTREF\";\n\n\n{-\n  # Address manipulation primitives\n  The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme:\n  ```TL-B\n  addr_none$00 = MsgAddressExt;\n  addr_extern$01 len:(## 8) external_address:(bits len)\n               = MsgAddressExt;\n  anycast_info$_ depth:(#<= 30) { depth >= 1 }\n    rewrite_pfx:(bits depth) = Anycast;\n  addr_std$10 anycast:(Maybe Anycast)\n    workchain_id:int8 address:bits256 = MsgAddressInt;\n  addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)\n    workchain_id:int32 address:(bits addr_len) = MsgAddressInt;\n  _ _:MsgAddressInt = MsgAddress;\n  _ _:MsgAddressExt = MsgAddress;\n\n  int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool\n    src:MsgAddress dest:MsgAddressInt\n    value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams\n    created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;\n  ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt\n    created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;\n  ```\n  A deserialized `MsgAddress` is represented by a tuple `t` as follows:\n\n  - `addr_none` is represented by `t = (0)`,\n    i.e., a tuple containing exactly one integer equal to zero.\n  - `addr_extern` is represented by `t = (1, s)`,\n    where slice `s` contains the field `external_address`. In other words, `\n    t` is a pair (a tuple consisting of two entries), containing an integer equal to one and slice `s`.\n  - `addr_std` is represented by `t = (2, u, x, s)`,\n    where `u` is either a `null` (if `anycast` is absent) or a slice `s'` containing `rewrite_pfx` (if anycast is present).\n    Next, integer `x` is the `workchain_id`, and slice `s` contains the address.\n  - `addr_var` is represented by `t = (3, u, x, s)`,\n    where `u`, `x`, and `s` have the same meaning as for `addr_std`.\n-}\n\n;;; Loads from slice [s] the only prefix that is a valid `MsgAddress`,\n;;; and returns both this prefix `s'` and the remainder `s''` of [s] as slices.\n(slice, slice) load_msg_addr(slice s) asm(-> 1 0) \"LDMSGADDR\";\n\n;;; Decomposes slice [s] containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`.\n;;; If [s] is not a valid `MsgAddress`, a cell deserialization exception is thrown.\ntuple parse_addr(slice s) asm \"PARSEMSGADDR\";\n\n;;; Parses slice [s] containing a valid `MsgAddressInt` (usually a `msg_addr_std`),\n;;; applies rewriting from the anycast (if present) to the same-length prefix of the address,\n;;; and returns both the workchain and the 256-bit address as integers.\n;;; If the address is not 256-bit, or if [s] is not a valid serialization of `MsgAddressInt`,\n;;; throws a cell deserialization exception.\n(int, int) parse_std_addr(slice s) asm \"REWRITESTDADDR\";\n\n;;; A variant of [parse_std_addr] that returns the (rewritten) address as a slice [s],\n;;; even if it is not exactly 256 bit long (represented by a `msg_addr_var`).\n(int, slice) parse_var_addr(slice s) asm \"REWRITEVARADDR\";\n\n{-\n  # Dictionary primitives\n-}\n\n\n;;; Sets the value associated with [key_len]-bit key signed index in dictionary [dict] to [value] (cell),\n;;; and returns the resulting dictionary.\ncell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTISETREF\";\n(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTISETREF\";\n\n;;; Sets the value associated with [key_len]-bit key unsigned index in dictionary [dict] to [value] (cell),\n;;; and returns the resulting dictionary.\ncell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTUSETREF\";\n(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTUSETREF\";\n\ncell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) \"DICTIGETOPTREF\";\n(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTIGETREF\" \"NULLSWAPIFNOT\";\n(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTUGETREF\" \"NULLSWAPIFNOT\";\n(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTISETGETOPTREF\";\n(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) \"DICTUSETGETOPTREF\";\n(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTIDEL\";\n(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTUDEL\";\n(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTIGET\" \"NULLSWAPIFNOT\";\n(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTUGET\" \"NULLSWAPIFNOT\";\n(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTIDELGET\" \"NULLSWAPIFNOT\";\n(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTUDELGET\" \"NULLSWAPIFNOT\";\n(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTIDELGET\" \"NULLSWAPIFNOT\";\n(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTUDELGET\" \"NULLSWAPIFNOT\";\ncell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTUSET\";\n(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTUSET\";\ncell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTISET\";\n(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTISET\";\ncell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) \"DICTSET\";\n(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) \"DICTSET\";\n(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTUADD\";\n(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTUREPLACE\";\n(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTIADD\";\n(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) \"DICTIREPLACE\";\ncell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTUSETB\";\n(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTUSETB\";\ncell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTISETB\";\n(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTISETB\";\ncell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) \"DICTSETB\";\n(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) \"DICTSETB\";\n(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTUADDB\";\n(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTUREPLACEB\";\n(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTIADDB\";\n(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) \"DICTIREPLACEB\";\n(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTUREMMIN\" \"NULLSWAPIFNOT2\";\n(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTUREMMIN\" \"NULLSWAPIFNOT2\";\n(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTIREMMIN\" \"NULLSWAPIFNOT2\";\n(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTIREMMIN\" \"NULLSWAPIFNOT2\";\n(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTREMMIN\" \"NULLSWAPIFNOT2\";\n(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTREMMIN\" \"NULLSWAPIFNOT2\";\n(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTUREMMAX\" \"NULLSWAPIFNOT2\";\n(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTUREMMAX\" \"NULLSWAPIFNOT2\";\n(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTIREMMAX\" \"NULLSWAPIFNOT2\";\n(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTIREMMAX\" \"NULLSWAPIFNOT2\";\n(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTREMMAX\" \"NULLSWAPIFNOT2\";\n(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) \"DICTREMMAX\" \"NULLSWAPIFNOT2\";\n(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) \"DICTUMIN\" \"NULLSWAPIFNOT2\";\n(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) \"DICTUMAX\" \"NULLSWAPIFNOT2\";\n(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) \"DICTUMINREF\" \"NULLSWAPIFNOT2\";\n(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) \"DICTUMAXREF\" \"NULLSWAPIFNOT2\";\n(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) \"DICTIMIN\" \"NULLSWAPIFNOT2\";\n(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) \"DICTIMAX\" \"NULLSWAPIFNOT2\";\n(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) \"DICTIMINREF\" \"NULLSWAPIFNOT2\";\n(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) \"DICTIMAXREF\" \"NULLSWAPIFNOT2\";\n(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTUGETNEXT\" \"NULLSWAPIFNOT2\";\n(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTUGETNEXTEQ\" \"NULLSWAPIFNOT2\";\n(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTUGETPREV\" \"NULLSWAPIFNOT2\";\n(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTUGETPREVEQ\" \"NULLSWAPIFNOT2\";\n(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTIGETNEXT\" \"NULLSWAPIFNOT2\";\n(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTIGETNEXTEQ\" \"NULLSWAPIFNOT2\";\n(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTIGETPREV\" \"NULLSWAPIFNOT2\";\n(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) \"DICTIGETPREVEQ\" \"NULLSWAPIFNOT2\";\n\n;;; Creates an empty dictionary, which is actually a null value. Equivalent to PUSHNULL\ncell new_dict() asm \"NEWDICT\";\n;;; Checks whether a dictionary is empty. Equivalent to cell_null?.\nint dict_empty?(cell c) asm \"DICTEMPTY\";\n\n\n{- Prefix dictionary primitives -}\n(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) \"PFXDICTGETQ\" \"NULLSWAPIFNOT2\";\n(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) \"PFXDICTSET\";\n(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) \"PFXDICTDEL\";\n\n;;; Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value.\ncell config_param(int x) asm \"CONFIGOPTPARAM\";\n;;; Checks whether c is a null. Note, that FunC also has polymorphic null? built-in.\nint cell_null?(cell c) asm \"ISNULL\";\n\n;;; Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15.\n() raw_reserve(int amount, int mode) impure asm \"RAWRESERVE\";\n;;; Similar to raw_reserve, but also accepts a dictionary extra_amount (represented by a cell or null) with extra currencies. In this way currencies other than TonCoin can be reserved.\n() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm \"RAWRESERVEX\";\n;;; Sends a raw message contained in msg, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value addr_none (to be automatically replaced with the current smart contract address), and ihr_fee, fwd_fee, created_lt and created_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter mode contains the flags. Currently mode = 0 is used for ordinary messages; mode = 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); mode = 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 (if bit 0 is not set, the gas fees are deducted from this amount); mode' = mode + 1 means that the sender wants to pay transfer fees separately; mode' = mode + 2 means that any errors arising while processing this message during the action phase should be ignored. Finally, mode' = mode + 32 means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128.\n() send_raw_message(cell msg, int mode) impure asm \"SENDRAWMSG\";\n;;; Creates an output action that would change this smart contract code to that given by cell new_code. Notice that this change will take effect only after the successful termination of the current run of the smart contract\n() set_code(cell new_code) impure asm \"SETCODE\";\n\n;;; Generates a new pseudo-random unsigned 256-bit integer x. The algorithm is as follows: if r is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its sha512(r) is computed; the first 32 bytes of this hash are stored as the new value r' of the random seed, and the remaining 32 bytes are returned as the next random value x.\nint random() impure asm \"RANDU256\";\n;;; Generates a new pseudo-random integer z in the range 0..range−1 (or range..−1, if range < 0). More precisely, an unsigned random value x is generated as in random; then z := x * range / 2^256 is computed.\nint rand(int range) impure asm \"RAND\";\n;;; Returns the current random seed as an unsigned 256-bit Integer.\nint get_seed() impure asm \"RANDSEED\";\n;;; Sets the random seed to unsigned 256-bit seed.\n() set_seed(int x) impure asm \"SETRAND\";\n;;; Mixes unsigned 256-bit integer x into the random seed r by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed r, and the second with the big-endian representation of x.\n() randomize(int x) impure asm \"ADDRAND\";\n;;; Equivalent to randomize(cur_lt());.\n() randomize_lt() impure asm \"LTIME\" \"ADDRAND\";\n\n;;; Checks whether the data parts of two slices coinside\nint equal_slices_bits(slice a, slice b) asm \"SDEQ\";\n;;; Checks whether b is a null. Note, that FunC also has polymorphic null? built-in.\nint builder_null?(builder b) asm \"ISNULL\";\n;;; Concatenates two builders\nbuilder store_builder(builder to, builder from) asm \"STBR\";\n\n;; CUSTOM:\n\n;; TVM UPGRADE 2023-07 https://docs.ton.org/learn/tvm-instructions/tvm-upgrade-2023-07\n;; In mainnet since 20 Dec 2023 https://t.me/tonblockchain/226\n\n;;; Retrieves code of smart-contract from c7\ncell my_code() asm \"MYCODE\";\n\n;;; Creates an output action and returns a fee for creating a message. Mode has the same effect as in the case of SENDRAWMSG\nint send_message(cell msg, int mode) impure asm \"SENDMSG\";\n\nint gas_consumed() asm \"GASCONSUMED\";\n\n;; TVM V6 https://github.com/ton-blockchain/ton/blob/testnet/doc/GlobalVersions.md#version-6\n\nint get_compute_fee(int workchain, int gas_used) asm(gas_used workchain) \"GETGASFEE\";\nint get_storage_fee(int workchain, int seconds, int bits, int cells) asm(cells bits seconds workchain) \"GETSTORAGEFEE\";\nint get_forward_fee(int workchain, int bits, int cells) asm(cells bits workchain) \"GETFORWARDFEE\";\nint get_precompiled_gas_consumption() asm \"GETPRECOMPILEDGAS\";\n\nint get_simple_compute_fee(int workchain, int gas_used) asm(gas_used workchain) \"GETGASFEESIMPLE\";\nint get_simple_forward_fee(int workchain, int bits, int cells) asm(cells bits workchain) \"GETFORWARDFEESIMPLE\";\nint get_original_fwd_fee(int workchain, int fwd_fee) asm(fwd_fee workchain) \"GETORIGINALFWDFEE\";\nint my_storage_due() asm \"DUEPAYMENT\";\n\ntuple get_fee_cofigs() asm \"UNPACKEDCONFIGTUPLE\";\n\n;; BASIC\n\nconst int TRUE = -1;\nconst int FALSE = 0;\n\nconst int MASTERCHAIN = -1;\nconst int BASECHAIN = 0;\n\n;;; skip (Maybe ^Cell) from `slice` [s].\n(slice, ()) ~skip_maybe_ref(slice s) asm \"SKIPOPTREF\";\n\n(slice, int) ~load_bool(slice s) inline {\n    return s.load_int(1);\n}\n\nbuilder store_bool(builder b, int value) inline {\n    return b.store_int(value, 1);\n}\n\n;; ADDRESS NONE\n;; addr_none$00 = MsgAddressExt; https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L100\n\nbuilder store_address_none(builder b) inline {\n    return b.store_uint(0, 2);\n}\n\nslice address_none() asm \"<b 0 2 u, b> <s PUSHSLICE\";\n\nint is_address_none(slice s) inline {\n    return s.preload_uint(2) == 0;\n}\n\n;; MESSAGE\n\n;; The message header info is organized as follows:\n\n;; https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L126\n;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool\n;; src:MsgAddressInt dest:MsgAddressInt\n;; value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams\n;; created_lt:uint64 created_at:uint32 = CommonMsgInfo;\n\n;; https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L135\n;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool\n;; src:MsgAddress dest:MsgAddressInt\n;; value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams\n;; created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed;\n\n\n;; https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L123C1-L124C33\n;; currencies$_ grams:Grams other:ExtraCurrencyCollection = CurrencyCollection;\n\n;; MSG FLAGS\n\nconst int BOUNCEABLE = 0x18; ;; 0b011000 tag - 0, ihr_disabled - 1, bounce - 1, bounced - 0, src = adr_none$00\nconst int NON_BOUNCEABLE = 0x10; ;; 0b010000 tag - 0, ihr_disabled - 1, bounce - 0, bounced - 0, src = adr_none$00\n\n;; store msg_flags and address none\nbuilder store_msg_flags_and_address_none(builder b, int msg_flags) inline {\n    return b.store_uint(msg_flags, 6);\n}\n\n;; load msg_flags only\n(slice, int) ~load_msg_flags(slice s) inline {\n    return s.load_uint(4);\n}\n;;; @param `msg_flags` - 4-bit\nint is_bounced(int msg_flags) inline {\n    return msg_flags & 1 == 1;\n}\n\n(slice, ()) ~skip_bounced_prefix(slice s) inline {\n    return (s.skip_bits(32), ()); ;; skip 0xFFFFFFFF prefix\n}\n\n;; after `grams:Grams` we have (1 + 4 + 4 + 64 + 32) zeroes - zeroed extracurrency, ihr_fee, fwd_fee, created_lt and created_at\nconst int MSG_INFO_REST_BITS = 1 + 4 + 4 + 64 + 32;\n\n;; MSG\n\n;; https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L155\n;; message$_ {X:Type} info:CommonMsgInfo\n;;  init:Maybe (Either StateInit ^StateInit)\n;;  body:(Either X ^X) = Message X;\n;;\n;;message$_ {X:Type} info:CommonMsgInfoRelaxed\n;;  init:(Maybe (Either StateInit ^StateInit))\n;;  body:(Either X ^X) = MessageRelaxed X;\n;;\n;;_ (Message Any) = MessageAny;\n\n;; if have StateInit (always place StateInit in ref):\n;; 0b11 for `Maybe (Either StateInit ^StateInit)` and 0b1 or 0b0 for `body:(Either X ^X)`\n\nconst int MSG_WITH_STATE_INIT_AND_BODY_SIZE = MSG_INFO_REST_BITS + 1 + 1 + 1;\nconst int MSG_HAVE_STATE_INIT = 4;\nconst int MSG_STATE_INIT_IN_REF = 2;\nconst int MSG_BODY_IN_REF = 1;\n\n;; if no StateInit:\n;; 0b0 for `Maybe (Either StateInit ^StateInit)` and 0b1 or 0b0 for `body:(Either X ^X)`\n\nconst int MSG_ONLY_BODY_SIZE = MSG_INFO_REST_BITS + 1 + 1;\n\nbuilder store_statinit_ref_and_body_ref(builder b, cell state_init, cell body) inline {\n    return b\n    .store_uint(MSG_HAVE_STATE_INIT + MSG_STATE_INIT_IN_REF + MSG_BODY_IN_REF, MSG_WITH_STATE_INIT_AND_BODY_SIZE)\n    .store_ref(state_init)\n    .store_ref(body);\n}\n\nbuilder store_only_body_ref(builder b, cell body) inline {\n    return b\n    .store_uint(MSG_BODY_IN_REF, MSG_ONLY_BODY_SIZE)\n    .store_ref(body);\n}\n\nbuilder store_prefix_only_body(builder b) inline {\n    return b\n    .store_uint(0, MSG_ONLY_BODY_SIZE);\n}\n\n;; parse after sender_address\n(slice, int) ~retrieve_fwd_fee(slice in_msg_full_slice) inline {\n    in_msg_full_slice~load_msg_addr(); ;; skip dst\n    in_msg_full_slice~load_coins(); ;; skip value\n    in_msg_full_slice~skip_dict(); ;; skip extracurrency collection\n    in_msg_full_slice~load_coins(); ;; skip ihr_fee\n    int fwd_fee = in_msg_full_slice~load_coins();\n    return (in_msg_full_slice, fwd_fee);\n}\n\n;; MSG BODY\n\n;; According to the guideline, it is recommended to start the body of the internal message with uint32 op and uint64 query_id\n\nconst int MSG_OP_SIZE = 32;\nconst int MSG_QUERY_ID_SIZE = 64;\n\n(slice, int) ~load_op(slice s) inline {\n    return s.load_uint(MSG_OP_SIZE);\n}\n(slice, ()) ~skip_op(slice s) inline {\n    return (s.skip_bits(MSG_OP_SIZE), ());\n}\nbuilder store_op(builder b, int op) inline {\n    return b.store_uint(op, MSG_OP_SIZE);\n}\n\n(slice, int) ~load_query_id(slice s) inline {\n    return s.load_uint(MSG_QUERY_ID_SIZE);\n}\n(slice, ()) ~skip_query_id(slice s) inline {\n    return (s.skip_bits(MSG_QUERY_ID_SIZE), ());\n}\nbuilder store_query_id(builder b, int query_id) inline {\n    return b.store_uint(query_id, MSG_QUERY_ID_SIZE);\n}\n\n(slice, (int, int)) ~load_op_and_query_id(slice s) inline {\n    int op = s~load_op();\n    int query_id = s~load_query_id();\n    return (s, (op, query_id));\n}\n\n;; SEND MODES - https://docs.ton.org/tvm.pdf page 137, SENDRAWMSG\n\n;; For `send_raw_message` and `send_message`:\n\n;;; x = 0 is used for ordinary messages; the gas fees are deducted from the senging amount; action phaes should NOT be ignored.\nconst int SEND_MODE_REGULAR = 0;\n;;; +1 means that the sender wants to pay transfer fees separately.\nconst int SEND_MODE_PAY_FEES_SEPARATELY = 1;\n;;; + 2 means that any errors arising while processing this message during the action phase should be ignored.\nconst int SEND_MODE_IGNORE_ERRORS = 2;\n;;; + 32 means that the current account must be destroyed if its resulting balance is zero.\nconst int SEND_MODE_DESTROY = 32;\n;;; 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.\nconst int SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE = 64;\n;;; 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).\nconst int SEND_MODE_CARRY_ALL_BALANCE = 128;\n;;; in the case of action fail - bounce transaction. No effect if SEND_MODE_IGNORE_ERRORS (+2) is used. TVM UPGRADE 2023-07. https://docs.ton.org/learn/tvm-instructions/tvm-upgrade-2023-07#sending-messages\nconst int SEND_MODE_BOUNCE_ON_ACTION_FAIL = 16;\n\n;; Only for `send_message`:\n\n;;; do not create an action, only estimate fee. TVM UPGRADE 2023-07. https://docs.ton.org/learn/tvm-instructions/tvm-upgrade-2023-07#sending-messages\nconst int SEND_MODE_ESTIMATE_FEE_ONLY = 1024;\n\n;; Other modes affect the fee calculation as follows:\n;; +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).\n;; +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).\n\n;; RESERVE MODES - https://docs.ton.org/tvm.pdf page 137, RAWRESERVE\n\n;;; Creates an output action which would reserve exactly x nanograms (if y = 0).\nconst int RESERVE_REGULAR = 0;\n;;; Creates an output action which would reserve at most x nanograms (if y = 2).\n;;; 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.\nconst int RESERVE_AT_MOST = 2;\n;;; in the case of action fail - bounce transaction. No effect if RESERVE_AT_MOST (+2) is used. TVM UPGRADE 2023-07. https://docs.ton.org/learn/tvm-instructions/tvm-upgrade-2023-07#sending-messages\nconst int RESERVE_BOUNCE_ON_ACTION_FAIL = 16;\n\n;; TOKEN METADATA\n;; https://github.com/ton-blockchain/TEPs/blob/master/text/0064-token-data-standard.md\n\n;; Key is sha256 hash of string. Value is data encoded as described in \"Data serialization\" paragraph.\n;; Snake format - must be prefixed with 0x00 byte\n(cell, ()) ~set_token_snake_metadata_entry(cell content_dict, int key, slice value) impure {\n    content_dict~udict_set_ref(256, key, begin_cell().store_uint(0, 8).store_slice(value).end_cell());\n    return (content_dict, ());\n}\n\n;; On-chain content layout The first byte is 0x00 and the rest is key/value dictionary.\ncell create_token_onchain_metadata(cell content_dict) inline {\n    return begin_cell().store_uint(0, 8).store_dict(content_dict).end_cell();\n}","is_entrypoint":false,"is_std_lib":false,"include_in_command":false},{"name":"jetton-utils.fc","content":"#include \"workchain.fc\";\n\nconst int STATUS_SIZE = 4;\n\ncell pack_jetton_wallet_data(int status, int balance, slice owner_address, slice jetton_master_address) inline {\n    return begin_cell()\n    .store_uint(status, STATUS_SIZE)\n    .store_coins(balance)\n    .store_slice(owner_address)\n    .store_slice(jetton_master_address)\n    .end_cell();\n}\n\ncell calculate_jetton_wallet_state_init(slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {\n    {-\n    https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L144\n    _ split_depth:(Maybe (## 5)) special:(Maybe TickTock)\n    code:(Maybe ^Cell) data:(Maybe ^Cell)\n    library:(Maybe ^Cell) = StateInit;\n  -}\n    return begin_cell()\n    .store_uint(0, 2) ;; 0b00 - No split_depth; No special\n    .store_maybe_ref(jetton_wallet_code)\n    .store_maybe_ref(\n        pack_jetton_wallet_data(\n            0, ;; status\n            0, ;; balance\n            owner_address,\n            jetton_master_address)\n    )\n    .store_uint(0, 1) ;; Empty libraries\n    .end_cell();\n}\n\nslice calculate_jetton_wallet_address(cell state_init) inline {\n    {-\n    https://github.com/ton-blockchain/ton/blob/8a9ff339927b22b72819c5125428b70c406da631/crypto/block/block.tlb#L105\n    addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256  = MsgAddressInt;\n    -}\n    return begin_cell()\n    .store_uint(4, 3) ;; 0b100 = addr_std$10 tag; No anycast\n    .store_int(MY_WORKCHAIN, 8)\n    .store_uint(cell_hash(state_init), 256)\n    .end_cell()\n    .begin_parse();\n}\n\nslice calculate_user_jetton_wallet_address(slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {\n    return calculate_jetton_wallet_address(calculate_jetton_wallet_state_init(owner_address, jetton_master_address, jetton_wallet_code));\n}\n\n() check_either_forward_payload(slice s) impure inline {\n    if (s.preload_uint(1)) {\n        ;; forward_payload in ref\n        (int remain_bits, int remain_refs) = slice_bits_refs(s);\n        throw_unless(error::invalid_message, (remain_refs == 1) & (remain_bits == 1)); ;; we check that there is no excess in the slice\n    }\n    ;; else forward_payload in slice - arbitrary bits and refs\n}","is_entrypoint":false,"is_std_lib":false,"include_in_command":true},{"name":"src/token/jetton-minter.fc","content":";; Jetton minter smart contract\n\n#pragma version >=0.4.3;\n\n#include \"stdlib.fc\";\n#include \"op-codes.fc\";\n#include \"workchain.fc\";\n#include \"jetton-utils.fc\";\n#include \"gas.fc\";\n\n;; storage#_ total_supply:Coins admin_address:MsgAddress next_admin_address:MsgAddress mint_to_authority:MsgAddress jetton_wallet_code:^Cell metadata_uri:^Cell = Storage;\n(int, slice, slice, slice, cell, cell) load_data() inline method_id {\n    slice ds = get_data().begin_parse();\n    var data = (\n        ds~load_coins(), ;; total_supply\n        ds~load_msg_addr(), ;; admin_address\n        ds~load_msg_addr(), ;; next_admin_address\n        ds~load_msg_addr(), ;; mint_to_authority (OFT contract)\n        ds~load_ref(),  ;; jetton_wallet_code\n        ds~load_ref()  ;; metadata url (contains snake slice without 0x0 prefix)\n    );\n    ds.end_parse();\n    return data;\n}\n\n() save_data(\n    int total_supply,\n    slice admin_address,\n    slice next_admin_address,\n    slice mint_to_authority,\n    cell jetton_wallet_code,\n    cell metadata_uri\n) impure inline {\n    set_data(\n        begin_cell()\n        .store_coins(total_supply) ;; TON coin format, variable between 4 and 124 bits\n        .store_slice(admin_address) ;; + 267 = 395\n        .store_slice(next_admin_address) ;; + 267 = 662\n        .store_slice(mint_to_authority) ;; + 267 = 929\n        .store_ref(jetton_wallet_code)\n        .store_ref(metadata_uri)\n        .end_cell()\n    );\n}\n\n() send_to_jetton_wallet(\n    slice to_address,\n    cell jetton_wallet_code,\n    int ton_amount,\n    cell master_msg,\n    int need_state_init\n) impure inline {\n    raw_reserve(ONE_TON, RESERVE_REGULAR); ;; reserve for storage fees\n\n    cell state_init = calculate_jetton_wallet_state_init(to_address, my_address(), jetton_wallet_code);\n    slice to_wallet_address = calculate_jetton_wallet_address(state_init);\n\n    ;; build MessageRelaxed, see TL-B layout in stdlib.fc#L733\n    var msg = begin_cell()\n        .store_msg_flags_and_address_none(BOUNCEABLE)\n        .store_slice(to_wallet_address) ;; dest\n        .store_coins(ton_amount);\n\n    if (need_state_init) {\n        msg = msg.store_statinit_ref_and_body_ref(state_init, master_msg);\n    } else {\n        msg = msg.store_only_body_ref(master_msg);\n    }\n\n    send_raw_message(msg.end_cell(), SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_BOUNCE_ON_ACTION_FAIL);\n}\n\n;; Receive jettons from a wallet and burn them\n;; Send a forward the payload to the OFT contract\n() receive_jettons(\n    slice in_msg_body,\n    slice sender_address,\n    int my_ton_balance,\n    int msg_value,\n    int query_id\n) impure inline_ref {\n    (\n        int total_supply,\n        slice admin_address,\n        slice next_admin_address,\n        slice mint_to_authority,\n        cell jetton_wallet_code,\n        cell metadata_uri\n    ) = load_data();\n    ;; see internal TL-B layout in jetton.tlb\n    int jetton_amount = in_msg_body~load_coins();\n    total_supply -= jetton_amount;\n    slice from_address = in_msg_body~load_msg_addr();\n    slice response_address = in_msg_body~load_msg_addr();\n    throw_unless(error::not_valid_wallet,\n        equal_slices_bits(calculate_user_jetton_wallet_address(from_address, my_address(), jetton_wallet_code), sender_address)\n    );\n    int forward_ton_amount = in_msg_body~load_coins();\n\n    if (forward_ton_amount) {\n        slice either_forward_payload = in_msg_body;\n\n        ;; see transfer_notification TL-B layout in jetton.tlb\n        cell msg_body = begin_cell()\n            .store_op(op::transfer_notification)\n            .store_query_id(query_id)\n            .store_coins(jetton_amount)\n            .store_slice(from_address)\n            .store_slice(either_forward_payload)\n            .end_cell();\n\n        ;; build MessageRelaxed, see TL-B layout in stdlib.fc#L733\n        cell msg = begin_cell()\n            .store_msg_flags_and_address_none(NON_BOUNCEABLE)\n            .store_slice(mint_to_authority)\n            .store_coins(forward_ton_amount)\n            .store_only_body_ref(msg_body)\n            .end_cell();\n\n        send_raw_message(msg, SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_BOUNCE_ON_ACTION_FAIL);\n    }\n\n    if (~ is_address_none(response_address)) {\n        ;; minter pays its own rent\n        int to_leave_on_balance = my_ton_balance - msg_value;\n        ;; If the balance is not enough, bounce the message back to sender to return the money\n        raw_reserve(to_leave_on_balance, RESERVE_BOUNCE_ON_ACTION_FAIL);\n\n        ;; build MessageRelaxed, see TL-B layout in stdlib.fc#L733\n        cell msg = begin_cell()\n            .store_msg_flags_and_address_none(NON_BOUNCEABLE)\n            .store_slice(response_address)\n            .store_coins(0)\n            .store_prefix_only_body()\n            .store_op(op::excesses)\n            .store_query_id(query_id)\n            .end_cell();\n        send_raw_message(msg, SEND_MODE_CARRY_ALL_BALANCE | SEND_MODE_IGNORE_ERRORS);\n    }\n    save_data(\n        total_supply,\n        admin_address,\n        next_admin_address,\n        mint_to_authority,\n        jetton_wallet_code,\n        metadata_uri\n    );\n}\n\n() recv_internal(int my_ton_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {\n    slice in_msg_full_slice = in_msg_full.begin_parse();\n    int msg_flags = in_msg_full_slice~load_msg_flags();\n\n    if (msg_flags & 1) { ;; is bounced\n        in_msg_body~skip_bounced_prefix();\n        ;; process only mint bounces\n        ifnot (in_msg_body~load_op() == op::internal_transfer) {\n            return ();\n        }\n        in_msg_body~skip_query_id();\n        int jetton_amount = in_msg_body~load_coins();\n        (int total_supply, slice admin_address, slice next_admin_address, slice mint_to_authority, cell jetton_wallet_code, cell metadata_uri) = load_data();\n        save_data(total_supply - jetton_amount, admin_address, next_admin_address, mint_to_authority, jetton_wallet_code, metadata_uri);\n        return ();\n    }\n    slice sender_address = in_msg_full_slice~load_msg_addr();\n    int fwd_fee_from_in_msg = in_msg_full_slice~retrieve_fwd_fee();\n    int fwd_fee = get_original_fwd_fee(MY_WORKCHAIN, fwd_fee_from_in_msg); ;; we use message fwd_fee for estimation of forward_payload costs\n\n    (int op, int query_id) = in_msg_body~load_op_and_query_id();\n\n    (\n        int total_supply,\n        slice admin_address,\n        slice next_admin_address,\n        slice mint_to_authority,\n        cell jetton_wallet_code,\n        cell metadata_uri\n    ) = load_data();\n\n    if (op == op::mint) {\n        throw_unless(error::not_minter,\n            equal_slices_bits(sender_address, admin_address)\n            | equal_slices_bits(sender_address, mint_to_authority)\n        );\n        slice to_address = in_msg_body~load_msg_addr();\n        check_same_workchain(to_address);\n        int ton_amount = in_msg_body~load_coins();\n        cell master_msg = in_msg_body~load_ref();\n        in_msg_body.end_parse();\n\n        ;; see internal_transfer TL-B layout in jetton.tlb\n        slice master_msg_slice = master_msg.begin_parse();\n        throw_unless(error::invalid_op, master_msg_slice~load_op() == op::internal_transfer);\n        master_msg_slice~skip_query_id();\n        int jetton_amount = master_msg_slice~load_coins();\n        master_msg_slice~load_msg_addr(); ;; from_address\n        master_msg_slice~load_msg_addr(); ;; response_address\n        int forward_ton_amount = master_msg_slice~load_coins(); ;; forward_ton_amount\n        check_either_forward_payload(master_msg_slice); ;; either_forward_payload\n\n        ;; a little more than needed, it’s ok since it’s sent by the admin and excesses will return back\n        check_amount_is_enough_to_transfer(ton_amount, forward_ton_amount, fwd_fee);\n\n        send_to_jetton_wallet(to_address, jetton_wallet_code, ton_amount, master_msg, TRUE);\n        save_data(\n            total_supply + jetton_amount,\n            admin_address,\n            next_admin_address,\n            mint_to_authority,\n            jetton_wallet_code,\n            metadata_uri\n        );\n        return ();\n    }\n\n    ;; incoming transfer\n    if (op == op::internal_transfer) {\n        return receive_jettons(in_msg_body, sender_address, my_ton_balance, msg_value, query_id);\n    }\n\n    if (op == op::burn_notification) {\n        ;; see burn_notification TL-B layout in jetton.tlb\n        int jetton_amount = in_msg_body~load_coins();\n        slice from_address = in_msg_body~load_msg_addr();\n        throw_unless(error::not_valid_wallet,\n            equal_slices_bits(\n                calculate_user_jetton_wallet_address(from_address, my_address(), jetton_wallet_code),\n                sender_address\n            )\n        );\n        save_data(\n            total_supply - jetton_amount,\n            admin_address,\n            next_admin_address,\n            mint_to_authority,\n            jetton_wallet_code,\n            metadata_uri\n        );\n        slice response_address = in_msg_body~load_msg_addr();\n        in_msg_body.end_parse();\n\n        if (~ is_address_none(response_address)) {\n            ;; build MessageRelaxed, see TL-B layout in stdlib.fc#L733\n            var msg = begin_cell()\n                .store_msg_flags_and_address_none(NON_BOUNCEABLE)\n                .store_slice(response_address) ;; dest\n                .store_coins(0)\n                .store_prefix_only_body()\n                .store_op(op::excesses)\n                .store_query_id(query_id);\n            send_raw_message(msg.end_cell(), SEND_MODE_IGNORE_ERRORS | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE);\n        }\n        return ();\n    }\n\n    if (op == op::provide_wallet_address) {\n        ;; see provide_wallet_address TL-B layout in jetton.tlb\n        slice owner_address = in_msg_body~load_msg_addr();\n        int include_address? = in_msg_body~load_bool();\n        in_msg_body.end_parse();\n\n        cell included_address = include_address?\n            ? begin_cell().store_slice(owner_address).end_cell()\n            : null();\n\n        ;; build MessageRelaxed, see TL-B layout in stdlib.fc#L733\n        var msg = begin_cell()\n            .store_msg_flags_and_address_none(NON_BOUNCEABLE)\n            .store_slice(sender_address)\n            .store_coins(0)\n            .store_prefix_only_body()\n            .store_op(op::take_wallet_address)\n            .store_query_id(query_id);\n\n        if (is_same_workchain(owner_address)) {\n            msg = msg.store_slice(calculate_user_jetton_wallet_address(owner_address, my_address(), jetton_wallet_code));\n        } else {\n            msg = msg.store_address_none();\n        }\n\n        cell msg_cell = msg.store_maybe_ref(included_address).end_cell();\n\n        send_raw_message(msg_cell, SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE | SEND_MODE_BOUNCE_ON_ACTION_FAIL);\n        return ();\n    }\n\n    if (op == op::change_admin) {\n        throw_unless(error::not_owner, equal_slices_bits(sender_address, admin_address));\n        next_admin_address = in_msg_body~load_msg_addr();\n        in_msg_body.end_parse();\n        save_data(\n            total_supply,\n            admin_address,\n            next_admin_address,\n            mint_to_authority,\n            jetton_wallet_code,\n            metadata_uri\n        );\n        return ();\n    }\n\n    if (op == op::claim_admin) {\n        in_msg_body.end_parse();\n        throw_unless(error::not_owner, equal_slices_bits(sender_address, next_admin_address));\n        save_data(\n            total_supply,\n            next_admin_address,\n            address_none(),\n            mint_to_authority,\n            jetton_wallet_code,\n            metadata_uri\n        );\n        return ();\n    }\n\n    ;; can be used to lock, unlock or reedem funds\n    if (op == op::call_to) {\n        throw_unless(error::not_owner, equal_slices_bits(sender_address, admin_address));\n        slice to_address = in_msg_body~load_msg_addr();\n        int ton_amount = in_msg_body~load_coins();\n        cell master_msg = in_msg_body~load_ref();\n        in_msg_body.end_parse();\n\n        slice master_msg_slice = master_msg.begin_parse();\n        int master_op = master_msg_slice~load_op();\n        master_msg_slice~skip_query_id();\n        ;; parse-validate messages\n        if (master_op == op::transfer) {\n            ;; see transfer TL-B layout in jetton.tlb\n            master_msg_slice~load_coins(); ;; jetton_amount\n            master_msg_slice~load_msg_addr(); ;; to_owner_address\n            master_msg_slice~load_msg_addr(); ;; response_address\n            master_msg_slice~skip_maybe_ref(); ;; custom_payload\n            int forward_ton_amount = master_msg_slice~load_coins(); ;; forward_ton_amount\n            check_either_forward_payload(master_msg_slice); ;; either_forward_payload\n\n            check_amount_is_enough_to_transfer(ton_amount, forward_ton_amount, fwd_fee);\n\n        } elseif (master_op == op::burn) {\n            ;; see burn TL-B layout in jetton.tlb\n            master_msg_slice~load_coins(); ;; jetton_amount\n            master_msg_slice~load_msg_addr(); ;; response_address\n            master_msg_slice~skip_maybe_ref(); ;; custom_payload\n            master_msg_slice.end_parse();\n\n            check_amount_is_enough_to_burn(ton_amount);\n\n        } elseif (master_op == op::set_status) {\n            master_msg_slice~load_uint(STATUS_SIZE); ;; status\n            master_msg_slice.end_parse();\n        } else {\n            throw(error::invalid_op);\n        }\n        send_to_jetton_wallet(to_address, jetton_wallet_code, ton_amount, master_msg, FALSE);\n        return ();\n    }\n\n    if (op == op::change_metadata_uri) {\n        throw_unless(error::not_owner, equal_slices_bits(sender_address, admin_address));\n        save_data(\n            total_supply,\n            admin_address,\n            next_admin_address,\n            mint_to_authority,\n            jetton_wallet_code,\n            begin_cell().store_slice(in_msg_body).end_cell()\n        );\n        return ();\n    }\n\n    if (op == op::upgrade) {\n        throw_unless(error::not_owner, equal_slices_bits(sender_address, admin_address));\n        (\n            cell new_data,\n            cell new_code\n        ) = (in_msg_body~load_ref(), in_msg_body~load_ref());\n        in_msg_body.end_parse();\n        set_data(new_data);\n        set_code(new_code);\n        return ();\n    }\n\n    if (op == op::top_up) {\n        return (); ;; just accept tons\n    }\n\n    throw(error::wrong_op);\n}\n\ncell build_content_cell(slice metadata_uri) inline {\n    cell content_dict = new_dict();\n    content_dict~set_token_snake_metadata_entry(\"uri\"H, metadata_uri);\n    content_dict~set_token_snake_metadata_entry(\"decimals\"H, \"6\");\n    return create_token_onchain_metadata(content_dict);\n}\n\n(int, int, slice, cell, cell) get_jetton_data() method_id {\n    (\n        int total_supply,\n        slice admin_address,\n        slice next_admin_address,\n        slice mint_to_authority,\n        cell jetton_wallet_code,\n        cell metadata_uri\n    ) = load_data();\n    return (total_supply, TRUE, admin_address, build_content_cell(metadata_uri.begin_parse()), jetton_wallet_code);\n}\n\nslice get_wallet_address(slice owner_address) method_id {\n    (\n        int total_supply,\n        slice admin_address,\n        slice next_admin_address,\n        slice mint_to_authority,\n        cell jetton_wallet_code,\n        cell metadata_uri\n    ) = load_data();\n    return calculate_user_jetton_wallet_address(owner_address, my_address(), jetton_wallet_code);\n}\n\nslice get_next_admin_address() method_id {\n    (\n        int total_supply,\n        slice admin_address,\n        slice next_admin_address,\n        slice mint_to_authority,\n        cell jetton_wallet_code,\n        cell metadata_uri\n    ) = load_data();\n    return next_admin_address;\n}","is_entrypoint":true,"is_std_lib":false,"include_in_command":true},{"name":"src/token/gas.fc","content":"#include \"workchain.fc\";\n\nconst ONE_TON = 1000000000;\n\nconst MIN_STORAGE_DURATION = 5 * 365 * 24 * 3600; ;; 5 years\n\n;;# Precompiled constants\n;;\n;;All of the contents are result of contract emulation tests\n;;\n\n;;## Minimal fees\n;;\n;;- Transfer [/sandbox_tests/JettonWallet.spec.ts#L935](L935) `0.028627415` TON\n;;- Burn [/sandbox_tests/JettonWallet.spec.ts#L1185](L1185) `0.016492002` TON\n\n\n;;## Storage\n;;\n;;Get calculated in a separate test file [/sandbox_tests/StateInit.spec.ts](StateInit.spec.ts)\n\n;;- `JETTON_WALLET_BITS` [/sandbox_tests/StateInit.spec.ts#L92](L92)\nconst JETTON_WALLET_BITS  = 1033;\n\n;;- `JETTON_WALLET_CELLS`: [/sandbox_tests/StateInit.spec.ts#L92](L92)\nconst JETTON_WALLET_CELLS = 3;\n\n;; difference in JETTON_WALLET_BITS/JETTON_WALLET_INITSTATE_BITS is difference in\n;; StateInit and AccountStorage (https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb)\n;; we count bits as if balances are max possible\n;;- `JETTON_WALLET_INITSTATE_BITS` [/sandbox_tests/StateInit.spec.ts#L95](L95)\nconst JETTON_WALLET_INITSTATE_BITS  = 931;\n;;- `JETTON_WALLET_INITSTATE_CELLS` [/sandbox_tests/StateInit.spec.ts#L95](L95)\nconst JETTON_WALLET_INITSTATE_CELLS = 3;\n\n;; jetton-wallet.fc#L163 - maunal bits counting\nconst BURN_NOTIFICATION_BITS = 754; ;; body = 32+64+124+(3+8+256)+(3+8+256)\nconst BURN_NOTIFICATION_CELLS = 1; ;; body always in ref\n\n;;## Gas\n;;\n;;Gas constants are calculated in the main test suite.\n;;First the related transaction is found, and then it's\n;;resulting gas consumption is printed to the console.\n\n;;- `SEND_TRANSFER_GAS_CONSUMPTION` [/sandbox_tests/JettonWallet.spec.ts#L853](L853)\nconst SEND_TRANSFER_GAS_CONSUMPTION    = 9400;\n\n;;- `RECEIVE_TRANSFER_GAS_CONSUMPTION` [/sandbox_tests/JettonWallet.spec.ts#L862](L862)\nconst RECEIVE_TRANSFER_GAS_CONSUMPTION = 10355;\n\n;;- `SEND_BURN_GAS_CONSUMPTION` [/sandbox_tests/JettonWallet.spec.ts#L1154](L1154)\nconst SEND_BURN_GAS_CONSUMPTION    = 6159;\n\n;;- `RECEIVE_BURN_GAS_CONSUMPTION` [/sandbox_tests/JettonWallet.spec.ts#L1155](L1155)\nconst RECEIVE_BURN_GAS_CONSUMPTION = 7076;\n\n\nint calculate_jetton_wallet_min_storage_fee() inline {\n    return get_storage_fee(MY_WORKCHAIN, MIN_STORAGE_DURATION, JETTON_WALLET_BITS, JETTON_WALLET_CELLS);\n}\n\nint forward_init_state_overhead() inline {\n    return get_simple_forward_fee(MY_WORKCHAIN, JETTON_WALLET_INITSTATE_BITS, JETTON_WALLET_INITSTATE_CELLS);\n}\n\n() check_amount_is_enough_to_transfer(int msg_value, int forward_ton_amount, int fwd_fee) impure inline {\n    int fwd_count = forward_ton_amount ? 2 : 1; ;; second sending (forward) will be cheaper that first\n\n    int jetton_wallet_gas_consumption = get_precompiled_gas_consumption();\n    int send_transfer_gas_consumption = null?(jetton_wallet_gas_consumption) ? SEND_TRANSFER_GAS_CONSUMPTION : jetton_wallet_gas_consumption;\n    int receive_transfer_gas_consumption = null?(jetton_wallet_gas_consumption) ? RECEIVE_TRANSFER_GAS_CONSUMPTION : jetton_wallet_gas_consumption;\n\n    throw_unless(error::not_enough_gas, msg_value >\n    forward_ton_amount +\n    ;; 3 messages: wal1->wal2,  wal2->owner, wal2->response\n    ;; but last one is optional (it is ok if it fails)\n    fwd_count * fwd_fee +\n    forward_init_state_overhead() + ;; additional fwd fees related to initstate in iternal_transfer\n    get_compute_fee(MY_WORKCHAIN, send_transfer_gas_consumption) +\n    get_compute_fee(MY_WORKCHAIN, receive_transfer_gas_consumption) +\n    calculate_jetton_wallet_min_storage_fee() );\n}\n\n() check_amount_is_enough_to_burn(int msg_value) impure inline {\n    int jetton_wallet_gas_consumption = get_precompiled_gas_consumption();\n    int send_burn_gas_consumption = null?(jetton_wallet_gas_consumption) ? SEND_BURN_GAS_CONSUMPTION : jetton_wallet_gas_consumption;\n\n    throw_unless(error::not_enough_gas, msg_value > get_forward_fee(MY_WORKCHAIN, BURN_NOTIFICATION_BITS, BURN_NOTIFICATION_CELLS) + get_compute_fee(MY_WORKCHAIN, send_burn_gas_consumption) + get_compute_fee(MY_WORKCHAIN, RECEIVE_BURN_GAS_CONSUMPTION));\n}\n","is_entrypoint":false,"is_std_lib":false,"include_in_command":false},{"name":"src/token/op-codes.fc","content":";; common\n\nconst op::transfer = 0xf8a7ea5;\nconst op::transfer_notification = 0x7362d09c;\nconst op::internal_transfer = 0x178d4519;\nconst op::excesses = 0xd53276db;\nconst op::burn = 0x595f07bc;\nconst op::burn_notification = 0x7bdd97de;\n\nconst op::provide_wallet_address = 0x2c76b973;\nconst op::take_wallet_address = 0xd1735400;\n\nconst op::top_up = 0xd372158c;\n\nconst error::invalid_op = 72;\nconst error::wrong_op = 0xffff;\nconst error::not_owner = 73;\nconst error::not_valid_wallet = 74;\nconst error::not_minter = 75;\nconst error::wrong_workchain = 333;\n\n;; jetton-minter\n\nconst op::mint = 0x642b7d07;\nconst op::change_admin = 0x6501f354;\nconst op::claim_admin = 0xfb88e119;\nconst op::upgrade = 0x2508d66a;\nconst op::call_to = 0x235caf52;\nconst op::change_metadata_uri = 0xcb862902;\n\n;; jetton-wallet\n\nconst op::set_status = 0xeed236d3;\n\nconst error::contract_locked = 45;\nconst error::balance_error = 47;\nconst error::not_enough_gas = 48;\nconst error::invalid_message = 49;\n","is_entrypoint":false,"is_std_lib":false,"include_in_command":false},{"name":"contracts/workchain.fc","content":"#include \"stdlib.fc\";\n#include \"op-codes.fc\";\n\nconst MY_WORKCHAIN = BASECHAIN;\n\nint is_same_workchain(slice addr) inline {\n    (int wc, _) = parse_std_addr(addr);\n    return wc == MY_WORKCHAIN;\n}\n\n() check_same_workchain(slice addr) impure inline {\n    throw_unless(error::wrong_workchain, is_same_workchain(addr));\n}","is_entrypoint":false,"is_std_lib":false,"include_in_command":false}]}}