{
  "language": "FunC",
  "targets": {
    "master": [
      "jetton-master.fc"
    ],
    "wallet": [
      "imports/stdlib.fc",
      "imports/params.fc",
      "imports/op-codes.fc",
      "imports/jetton-utils.fc",
      "jetton-wallet.fc"
    ]
  },
  "sources": {
    "imports/stdlib.fc": ";; 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\nforall X -> tuple cons(X head, tuple tail) asm \"CONS\";\nforall X -> (X, tuple) uncons(tuple list) asm \"UNCONS\";\nforall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) \"UNCONS\";\nforall X -> X car(tuple list) asm \"CAR\";\ntuple cdr(tuple list) asm \"CDR\";\ntuple empty_tuple() asm \"NIL\";\nforall X -> tuple tpush(tuple t, X value) asm \"TPUSH\";\nforall X -> (tuple, ()) ~tpush(tuple t, X value) asm \"TPUSH\";\nforall X -> [X] single(X x) asm \"SINGLE\";\nforall X -> X unsingle([X] t) asm \"UNSINGLE\";\nforall X, Y -> [X, Y] pair(X x, Y y) asm \"PAIR\";\nforall X, Y -> (X, Y) unpair([X, Y] t) asm \"UNPAIR\";\nforall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm \"TRIPLE\";\nforall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm \"UNTRIPLE\";\nforall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm \"4 TUPLE\";\nforall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm \"4 UNTUPLE\";\nforall X -> X first(tuple t) asm \"FIRST\";\nforall X -> X second(tuple t) asm \"SECOND\";\nforall X -> X third(tuple t) asm \"THIRD\";\nforall X -> X fourth(tuple t) asm \"3 INDEX\";\nforall X, Y -> X pair_first([X, Y] p) asm \"FIRST\";\nforall X, Y -> Y pair_second([X, Y] p) asm \"SECOND\";\nforall X, Y, Z -> X triple_first([X, Y, Z] p) asm \"FIRST\";\nforall X, Y, Z -> Y triple_second([X, Y, Z] p) asm \"SECOND\";\nforall X, Y, Z -> Z triple_third([X, Y, Z] p) asm \"THIRD\";\nforall X -> X null() asm \"PUSHNULL\";\nforall X -> (X, ()) ~impure_touch(X x) impure asm \"NOP\";\n\nint now() asm \"NOW\";\nslice my_address() asm \"MYADDR\";\n[int, cell] get_balance() asm \"BALANCE\";\nint cur_lt() asm \"LTIME\";\nint block_lt() asm \"BLOCKLT\";\n\nint cell_hash(cell c) asm \"HASHCU\";\nint slice_hash(slice s) asm \"HASHSU\";\nint string_hash(slice s) asm \"SHA256U\";\n\nint check_signature(int hash, slice signature, int public_key) asm \"CHKSIGNU\";\nint check_data_signature(slice data, slice signature, int public_key) asm \"CHKSIGNS\";\n\n(int, int, int) compute_data_size(cell c, int max_cells) impure asm \"CDATASIZE\";\n(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm \"SDATASIZE\";\n(int, int, int, int) compute_data_size?(cell c, int max_cells) asm \"CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT\";\n(int, int, int, int) slice_compute_data_size?(cell c, int max_cells) asm \"SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT\";\n\n;; () throw_if(int excno, int cond) impure asm \"THROWARGIF\";\n\n() dump_stack() impure asm \"DUMPSTK\";\n\ncell get_data() asm \"c4 PUSH\";\n() set_data(cell c) impure asm \"c4 POP\";\ncont get_c3() impure asm \"c3 PUSH\";\n() set_c3(cont c) impure asm \"c3 POP\";\ncont bless(slice s) impure asm \"BLESS\";\n\n() accept_message() impure asm \"ACCEPT\";\n() set_gas_limit(int limit) impure asm \"SETGASLIMIT\";\n() commit() impure asm \"COMMIT\";\n() buy_gas(int gram) impure asm \"BUYGAS\";\n\nint min(int x, int y) asm \"MIN\";\nint max(int x, int y) asm \"MAX\";\n(int, int) minmax(int x, int y) asm \"MINMAX\";\nint abs(int x) asm \"ABS\";\n\nslice begin_parse(cell c) asm \"CTOS\";\n() end_parse(slice s) impure asm \"ENDS\";\n(slice, cell) load_ref(slice s) asm( -> 1 0) \"LDREF\";\ncell preload_ref(slice s) asm \"PLDREF\";\n;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) \"LDIX\";\n;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) \"LDUX\";\n;; int preload_int(slice s, int len) asm \"PLDIX\";\n;; int preload_uint(slice s, int len) asm \"PLDUX\";\n;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) \"LDSLICEX\";\n;; slice preload_bits(slice s, int len) asm \"PLDSLICEX\";\n(slice, int) load_grams(slice s) asm( -> 1 0) \"LDGRAMS\";\nslice skip_bits(slice s, int len) asm \"SDSKIPFIRST\";\n(slice, ()) ~skip_bits(slice s, int len) asm \"SDSKIPFIRST\";\nslice first_bits(slice s, int len) asm \"SDCUTFIRST\";\nslice skip_last_bits(slice s, int len) asm \"SDSKIPLAST\";\n(slice, ()) ~skip_last_bits(slice s, int len) asm \"SDSKIPLAST\";\nslice slice_last(slice s, int len) asm \"SDCUTLAST\";\n(slice, cell) load_dict(slice s) asm( -> 1 0) \"LDDICT\";\ncell preload_dict(slice s) asm \"PLDDICT\";\nslice skip_dict(slice s) asm \"SKIPDICT\";\n\n(slice, cell) load_maybe_ref(slice s) asm( -> 1 0) \"LDOPTREF\";\ncell preload_maybe_ref(slice s) asm \"PLDOPTREF\";\nbuilder store_maybe_ref(builder b, cell c) asm(c b) \"STOPTREF\";\n\nint cell_depth(cell c) asm \"CDEPTH\";\n\nint slice_refs(slice s) asm \"SREFS\";\nint slice_bits(slice s) asm \"SBITS\";\n(int, int) slice_bits_refs(slice s) asm \"SBITREFS\";\nint slice_empty?(slice s) asm \"SEMPTY\";\nint slice_data_empty?(slice s) asm \"SDEMPTY\";\nint slice_refs_empty?(slice s) asm \"SREMPTY\";\nint slice_depth(slice s) asm \"SDEPTH\";\n\nint builder_refs(builder b) asm \"BREFS\";\nint builder_bits(builder b) asm \"BBITS\";\nint builder_depth(builder b) asm \"BDEPTH\";\n\nbuilder begin_cell() asm \"NEWC\";\ncell end_cell(builder b) asm \"ENDC\";\nbuilder store_ref(builder b, cell c) asm(c b) \"STREF\";\n;; builder store_uint(builder b, int x, int len) asm(x b len) \"STUX\";\n;; builder store_int(builder b, int x, int len) asm(x b len) \"STIX\";\nbuilder store_slice(builder b, slice s) asm \"STSLICER\";\nbuilder store_grams(builder b, int x) asm \"STGRAMS\";\nbuilder store_dict(builder b, cell c) asm(c b) \"STDICT\";\n\n(slice, slice) load_msg_addr(slice s) asm( -> 1 0) \"LDMSGADDR\";\ntuple parse_addr(slice s) asm \"PARSEMSGADDR\";\n(int, int) parse_std_addr(slice s) asm \"REWRITESTDADDR\";\n(int, slice) parse_var_addr(slice s) asm \"REWRITEVARADDR\";\n\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\";\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\";\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\";\n(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) \"DICTUGETREF\";\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\";\ncell new_dict() asm \"NEWDICT\";\nint dict_empty?(cell c) asm \"DICTEMPTY\";\n\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\ncell config_param(int x) asm \"CONFIGOPTPARAM\";\nint cell_null?(cell c) asm \"ISNULL\";\n\n() raw_reserve(int amount, int mode) impure asm \"RAWRESERVE\";\n() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm \"RAWRESERVEX\";\n() send_raw_message(cell msg, int mode) impure asm \"SENDRAWMSG\";\n() set_code(cell new_code) impure asm \"SETCODE\";\n\nint random() impure asm \"RANDU256\";\nint rand(int range) impure asm \"RAND\";\nint get_seed() impure asm \"RANDSEED\";\nint set_seed() impure asm \"SETRAND\";\n() randomize(int x) impure asm \"ADDRAND\";\n() randomize_lt() impure asm \"LTIME\" \"ADDRAND\";\n\nbuilder store_coins(builder b, int x) asm \"STVARUINT16\";\n(slice, int) load_coins(slice s) asm( -> 1 0) \"LDVARUINT16\";\n\nint equal_slices (slice a, slice b) asm \"SDEQ\";\nint builder_null?(builder b) asm \"ISNULL\";\nbuilder store_builder(builder to, builder from) asm \"STBR\";\n\n",
    "imports/params.fc": "int workchain() asm \"0 PUSHINT\";\n\n() force_chain(slice addr) impure {\n  (int wc, _) = parse_std_addr(addr);\n  throw_unless(333, wc == workchain());\n}",
    "imports/op-codes.fc": "int op::transfer() asm \"0xf8a7ea5 PUSHINT\";\nint op::transfer_notification() asm \"0x7362d09c PUSHINT\";\nint op::internal_transfer() asm \"0x178d4519 PUSHINT\";\nint op::excesses() asm \"0xd53276db PUSHINT\";\nint op::burn() asm \"0x595f07bc PUSHINT\";\nint op::burn_notification() asm \"0x7bdd97de PUSHINT\";\n\n;; Minter\nint op::mint() asm \"21 PUSHINT\";\n",
    "imports/jetton-utils.fc": "cell pack_jetton_wallet_data(int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {\n   return  begin_cell()\n            .store_coins(balance)\n            .store_slice(owner_address)\n            .store_slice(jetton_master_address)\n            .store_ref(jetton_wallet_code)\n           .end_cell();\n}\n\ncell calculate_jetton_wallet_state_init(slice owner_address, slice jetton_master_address, cell jetton_wallet_code) inline {\n  return begin_cell()\n          .store_uint(0, 2)\n          .store_dict(jetton_wallet_code)\n          .store_dict(pack_jetton_wallet_data(0, owner_address, jetton_master_address, jetton_wallet_code))\n          .store_uint(0, 1)\n         .end_cell();\n}\n\nslice calculate_jetton_wallet_address(cell state_init) inline {\n  return begin_cell().store_uint(4, 3)\n                     .store_int(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",
    "jetton-wallet.fc": ";; Jetton Wallet Smart Contract\n\n{-\n\nNOTE that this tokens can be transferred within the same workchain.\n\nThis is suitable for most tokens, if you need tokens transferable between workchains there are two solutions:\n\n1) use more expensive but universal function to calculate message forward fee for arbitrary destination (see `misc/forward-fee-calc.cs`)\n\n2) use token holder proxies in target workchain (that way even 'non-universal' token can be used from any workchain)\n\n-}\n\nint min_tons_for_storage() asm \"10000000 PUSHINT\"; ;; 0.01 TON\n;; Note that 2 * gas_consumptions is expected to be able to cover fees on both wallets (sender and receiver)\n;; and also constant fees on inter-wallet interaction, in particular fwd fee on state_init transfer\n;; that means that you need to reconsider this fee when:\n;; a) jetton logic become more gas-heavy\n;; b) jetton-wallet code (sent with inter-wallet message) become larger or smaller\n;; c) global fee changes / different workchain\nint gas_consumption() asm \"15000000 PUSHINT\"; ;; 0.015 TON\n\n{-\n  Storage\n  storage#_ balance:Coins owner_address:MsgAddressInt jetton_master_address:MsgAddressInt jetton_wallet_code:^Cell = Storage;\n-}\n\n(int, slice, slice, cell) load_data() inline {\n  slice ds = get_data().begin_parse();\n  return (ds~load_coins(), ds~load_msg_addr(), ds~load_msg_addr(), ds~load_ref());\n}\n\n() save_data (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) impure inline {\n  set_data(pack_jetton_wallet_data(balance, owner_address, jetton_master_address, jetton_wallet_code));\n}\n\n{-\n  transfer query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress\n           response_destination:MsgAddress custom_payload:(Maybe ^Cell)\n           forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell)\n           = InternalMsgBody;\n  internal_transfer  query_id:uint64 amount:(VarUInteger 16) from:MsgAddress\n                     response_address:MsgAddress\n                     forward_ton_amount:(VarUInteger 16)\n                     forward_payload:(Either Cell ^Cell) \n                     = InternalMsgBody;\n-}\n\n() send_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {\n  int query_id = in_msg_body~load_uint(64);\n  int jetton_amount = in_msg_body~load_coins();\n  slice to_owner_address = in_msg_body~load_msg_addr();\n  force_chain(to_owner_address);\n  (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();\n  balance -= jetton_amount;\n\n  throw_unless(705, equal_slices(owner_address, sender_address));\n  throw_unless(706, balance >= 0);\n\n  cell state_init = calculate_jetton_wallet_state_init(to_owner_address, jetton_master_address, jetton_wallet_code);\n  slice to_wallet_address = calculate_jetton_wallet_address(state_init);\n  slice response_address = in_msg_body~load_msg_addr();\n  cell custom_payload = in_msg_body~load_dict();\n  int forward_ton_amount = in_msg_body~load_coins();\n  throw_unless(708, slice_bits(in_msg_body) >= 1);\n  slice either_forward_payload = in_msg_body;\n  var msg = begin_cell()\n    .store_uint(0x18, 6)\n    .store_slice(to_wallet_address)\n    .store_coins(0)\n    .store_uint(4 + 2 + 1, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)\n    .store_ref(state_init);\n  var msg_body = begin_cell()\n    .store_uint(op::internal_transfer(), 32)\n    .store_uint(query_id, 64)\n    .store_coins(jetton_amount)\n    .store_slice(owner_address)\n    .store_slice(response_address)\n    .store_coins(forward_ton_amount)\n    .store_slice(either_forward_payload)\n    .end_cell();\n\n  msg = msg.store_ref(msg_body);\n  int fwd_count = forward_ton_amount ? 2 : 1;\n  throw_unless(709, 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                     (2 * gas_consumption() + min_tons_for_storage()));\n                     ;; universal message send fee calculation may be activated here\n                     ;; by using this instead of fwd_fee\n                     ;; msg_fwd_fee(to_wallet, msg_body, state_init, 15)\n\n  send_raw_message(msg.end_cell(), 64); ;; revert on errors\n  save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);\n}\n\n{-\n  internal_transfer  query_id:uint64 amount:(VarUInteger 16) from:MsgAddress\n                     response_address:MsgAddress\n                     forward_ton_amount:(VarUInteger 16)\n                     forward_payload:(Either Cell ^Cell) \n                     = InternalMsgBody;\n-}\n\n() receive_tokens (slice in_msg_body, slice sender_address, int my_ton_balance, int fwd_fee, int msg_value) impure {\n  ;; NOTE we can not allow fails in action phase since in that case there will be\n  ;; no bounce. Thus check and throw in computation phase.\n  (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();\n  int query_id = in_msg_body~load_uint(64);\n  int jetton_amount = in_msg_body~load_coins();\n  balance += 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(707,\n      equal_slices(jetton_master_address, sender_address)\n      |\n      equal_slices(calculate_user_jetton_wallet_address(from_address, jetton_master_address, jetton_wallet_code), sender_address)\n  );\n  int forward_ton_amount = in_msg_body~load_coins();\n\n  int ton_balance_before_msg = my_ton_balance - msg_value;\n  int storage_fee = min_tons_for_storage() - min(ton_balance_before_msg, min_tons_for_storage());\n  msg_value -= (storage_fee + gas_consumption());\n  if(forward_ton_amount) {\n    msg_value -= (forward_ton_amount + fwd_fee);\n    slice either_forward_payload = in_msg_body;\n\n    var msg_body = begin_cell()\n        .store_uint(op::transfer_notification(), 32)\n        .store_uint(query_id, 64)\n        .store_coins(jetton_amount)\n        .store_slice(from_address)\n        .store_slice(either_forward_payload)\n        .end_cell();\n\n    var msg = begin_cell()\n      .store_uint(0x10, 6) ;; we should not bounce here cause receiver can have uninitialized contract\n      .store_slice(owner_address)\n      .store_coins(forward_ton_amount)\n      .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)\n      .store_ref(msg_body);\n\n    send_raw_message(msg.end_cell(), 1);\n  }\n\n  if ((response_address.preload_uint(2) != 0) & (msg_value > 0)) {\n    var msg = begin_cell()\n      .store_uint(0x10, 6) ;; nobounce - int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 010000\n      .store_slice(response_address)\n      .store_coins(msg_value)\n      .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)\n      .store_uint(op::excesses(), 32)\n      .store_uint(query_id, 64);\n    send_raw_message(msg.end_cell(), 2);\n  }\n\n  save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);\n}\n\n() burn_tokens (slice in_msg_body, slice sender_address, int msg_value, int fwd_fee) impure {\n  ;; NOTE we can not allow fails in action phase since in that case there will be\n  ;; no bounce. Thus check and throw in computation phase.\n  (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();\n  int query_id = in_msg_body~load_uint(64);\n  int jetton_amount = in_msg_body~load_coins();\n  slice response_address = in_msg_body~load_msg_addr();\n  ;; ignore custom payload\n  ;; slice custom_payload = in_msg_body~load_dict();\n  balance -= jetton_amount;\n  throw_unless(705, equal_slices(owner_address, sender_address));\n  throw_unless(706, balance >= 0);\n  throw_unless(707, msg_value > fwd_fee + 2 * gas_consumption());\n\n  var msg_body = begin_cell()\n      .store_uint(op::burn_notification(), 32)\n      .store_uint(query_id, 64)\n      .store_coins(jetton_amount)\n      .store_slice(owner_address)\n      .store_slice(response_address)\n      .end_cell();\n\n  var msg = begin_cell()\n    .store_uint(0x18, 6)\n    .store_slice(jetton_master_address)\n    .store_coins(0)\n    .store_uint(1, 1 + 4 + 4 + 64 + 32 + 1 + 1)\n    .store_ref(msg_body);\n\n  send_raw_message(msg.end_cell(), 64);\n\n  save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);\n}\n\n() on_bounce (slice in_msg_body) impure {\n  in_msg_body~skip_bits(32); ;; 0xFFFFFFFF\n  (int balance, slice owner_address, slice jetton_master_address, cell jetton_wallet_code) = load_data();\n  int op = in_msg_body~load_uint(32);\n  throw_unless(709, (op == op::internal_transfer()) | (op == op::burn_notification()));\n  int query_id = in_msg_body~load_uint(64);\n  int jetton_amount = in_msg_body~load_coins();\n  balance += jetton_amount;\n  save_data(balance, owner_address, jetton_master_address, jetton_wallet_code);\n}\n\n() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {\n  if (in_msg_body.slice_empty?()) { ;; ignore empty messages\n    return ();\n  }\n\n  slice cs = in_msg_full.begin_parse();\n  int flags = cs~load_uint(4);\n  if (flags & 1) {\n    on_bounce(in_msg_body);\n    return ();\n  }\n  slice sender_address = cs~load_msg_addr();\n  cs~load_msg_addr(); ;; skip dst\n  cs~load_coins(); ;; skip value\n  cs~skip_bits(1); ;; skip extracurrency collection\n  cs~load_coins(); ;; skip ihr_fee\n  int fwd_fee = muldiv(cs~load_coins(), 3, 2); ;; we use message fwd_fee for estimation of forward_payload costs\n\n  int op = in_msg_body~load_uint(32);\n\n  if (op == op::transfer()) { ;; outgoing transfer\n    send_tokens(in_msg_body, sender_address, msg_value, fwd_fee);\n    return ();\n  }\n\n  if (op == op::internal_transfer()) { ;; incoming transfer\n    receive_tokens(in_msg_body, sender_address, my_balance, fwd_fee, msg_value);\n    return ();\n  }\n\n  if (op == op::burn()) { ;; burn\n    burn_tokens(in_msg_body, sender_address, msg_value, fwd_fee);\n    return ();\n  }\n\n  throw(0xffff);\n}\n\n(int, slice, slice, cell) get_wallet_data() method_id {\n  return load_data();\n}\n",
    "jetton-master.fc": ";; Tylnyi Coin fixed-emission Jetton master. MIT.\n;; TEP-74 + wallet discovery TEP-89. Wallet code is pinned TON reference.\n#include \"imports/stdlib.fc\";\n#include \"imports/params.fc\";\n#include \"imports/op-codes.fc\";\n#include \"imports/jetton-utils.fc\";\n\nint fixed_supply() asm \"24102026000000000 PUSHINT\";\nint op::initialize() asm \"0x54494e49 PUSHINT\";\nint op::provide_wallet_address() asm \"0x2c76b973 PUSHINT\";\nint op::take_wallet_address() asm \"0xd1735400 PUSHINT\";\n\n;; supply:Coins bootstrap_state:uint2 treasury:MsgAddress init_query_id:uint64\n;; content:^Cell wallet_code:^Cell. States: 0 not issued, 1 in flight, 2 acked.\n(int, int, slice, int, cell, cell) load_data() inline {\n  slice ds = get_data().begin_parse();\n  return (ds~load_coins(), ds~load_uint(2), ds~load_msg_addr(),\n          ds~load_uint(64), ds~load_ref(), ds~load_ref());\n}\n() save_data(int supply, int state, slice treasury, int query_id, cell content, cell wallet_code) impure inline {\n  set_data(begin_cell().store_coins(supply).store_uint(state, 2)\n    .store_slice(treasury).store_uint(query_id, 64).store_ref(content)\n    .store_ref(wallet_code).end_cell());\n}\n\n() recv_internal(int msg_value, cell full_message, slice body) impure {\n  if (body.slice_empty?()) { return (); }\n  slice info = full_message.begin_parse();\n  int flags = info~load_uint(4);\n  slice sender = info~load_msg_addr();\n  (int supply, int state, slice treasury, int init_id, cell content, cell wallet_code) = load_data();\n  slice treasury_wallet = calculate_user_jetton_wallet_address(treasury, my_address(), wallet_code);\n  if (flags & 1) {\n    ;; Only the authentic initial internal_transfer bounce may reset issuance.\n    ;; Normal user-transfer/burn bounces are handled by the reference wallet.\n    body~skip_bits(32);\n    int bounced_op = body~load_uint(32);\n    if ((state == 1) & equal_slices(sender, treasury_wallet) & (bounced_op == op::internal_transfer())) {\n      int bounced_id = body~load_uint(64);\n      int bounced_amount = body~load_coins();\n      throw_unless(76, (bounced_id == init_id) & (bounced_amount == fixed_supply()) & (supply == fixed_supply()));\n      save_data(0, 0, treasury, 0, content, wallet_code);\n    }\n    return ();\n  }\n  int operation = body~load_uint(32);\n  int query_id = body~load_uint(64);\n  if (operation == op::initialize()) {\n    throw_unless(73, equal_slices(sender, treasury));\n    throw_unless(75, (state == 0) & (supply == 0));\n    body.end_parse();\n    force_chain(treasury);\n    ;; Retain storage/gas reserve; the standard wallet returns excesses as ack.\n    throw_unless(77, msg_value >= 400000000);\n    cell state_init = calculate_jetton_wallet_state_init(treasury, my_address(), wallet_code);\n    cell transfer = begin_cell().store_uint(op::internal_transfer(), 32)\n      .store_uint(query_id, 64).store_coins(fixed_supply()).store_uint(0, 2)\n      .store_slice(my_address()).store_coins(0).store_uint(0, 1).end_cell();\n    cell message = begin_cell().store_uint(0x18, 6).store_slice(treasury_wallet)\n      .store_coins(200000000).store_uint(7, 1 + 4 + 4 + 64 + 32 + 1 + 1 + 1)\n      .store_ref(state_init).store_ref(transfer).end_cell();\n    ;; Without IGNORE_ERRORS: insufficient action funds revert init state too.\n    send_raw_message(message, 1);\n    save_data(fixed_supply(), 1, treasury, query_id, content, wallet_code);\n    return ();\n  }\n  if (operation == op::excesses()) {\n    if (state == 1) {\n      throw_unless(74, equal_slices(sender, treasury_wallet));\n      throw_unless(76, query_id == init_id);\n      body.end_parse();\n      save_data(supply, 2, treasury, init_id, content, wallet_code);\n    }\n    return ();\n  }\n  if (operation == op::burn_notification()) {\n    int amount = body~load_coins();\n    slice owner = body~load_msg_addr();\n    slice response = body~load_msg_addr();\n    body.end_parse();\n    throw_unless(74, equal_slices(calculate_user_jetton_wallet_address(owner, my_address(), wallet_code), sender));\n    throw_unless(78, (state == 2) & (amount > 0) & (amount <= supply));\n    save_data(supply - amount, state, treasury, init_id, content, wallet_code);\n    if (response.preload_uint(2) != 0) {\n      send_raw_message(begin_cell().store_uint(0x10, 6).store_slice(response).store_coins(0)\n        .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1).store_uint(op::excesses(), 32)\n        .store_uint(query_id, 64).end_cell(), 64 + 2);\n    }\n    return ();\n  }\n  if (operation == op::provide_wallet_address()) {\n    throw_unless(77, msg_value >= 10000000);\n    slice owner = body~load_msg_addr();\n    int include_owner = body~load_uint(1);\n    body.end_parse();\n    cell included = include_owner ? begin_cell().store_slice(owner).end_cell() : null();\n    var response = begin_cell().store_uint(0x10, 6).store_slice(sender).store_coins(0)\n      .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1).store_uint(op::take_wallet_address(), 32).store_uint(query_id, 64);\n    (int wc, _) = parse_std_addr(owner);\n    if (wc == 0) {\n      response = response.store_slice(calculate_user_jetton_wallet_address(owner, my_address(), wallet_code));\n    } else {\n      response = response.store_uint(0, 2);\n    }\n    send_raw_message(response.store_maybe_ref(included).end_cell(), 64);\n    return ();\n  }\n  ;; No mint, change-admin, metadata-edit or upgrade opcode exists.\n  throw(65535);\n}\n\n(int, int, slice, cell, cell) get_jetton_data() method_id {\n  (int supply, int state, slice treasury, int init_id, cell content, cell wallet_code) = load_data();\n  slice admin = begin_cell().store_uint(0, 2).end_cell().begin_parse();\n  return (supply, 0, admin, content, wallet_code);\n}\nslice get_wallet_address(slice owner) method_id {\n  (_, _, _, _, _, cell wallet_code) = load_data();\n  return calculate_user_jetton_wallet_address(owner, my_address(), wallet_code);\n}\n(int, slice, int) get_bootstrap_data() method_id {\n  (_, int state, slice treasury, int init_id, _, _) = load_data();\n  return (state, treasury, init_id);\n}\n"
  },
  "sourcePin": {
    "repository": "https://github.com/ton-blockchain/token-contract",
    "commit": "1182ad99413242f09925d50e70ccb7e0e09f94d4"
  }
}