diff --git a/.gitattributes b/.gitattributes index 4240706..c50280b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,2 @@ * text=auto eol=lf -funcfiftlib.js linguist-vendored +src/fift/funcfiftlib.js linguist-vendored diff --git a/eslint.config.mjs b/eslint.config.mjs index 1fee7ff..24e391b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -87,6 +87,7 @@ export default tseslint.config( "unicorn/no-null": "off", "unicorn/no-lonely-if": "off", "unicorn/no-process-exit": "off", + "unicorn/prefer-module": "off", }, }, ) diff --git a/src/decompiler/source-map.ts b/src/decompiler/source-map.ts new file mode 100644 index 0000000..fd3dc22 --- /dev/null +++ b/src/decompiler/source-map.ts @@ -0,0 +1,24 @@ +import {readFileSync} from "node:fs" +import {compileFiftForSourceMap} from "../fift/compileFift" + +export type ProcedureHash = string + +export type SourceMap = Map + +/** + * Extracts a source map from a Fift assembly file that was generated by Tact/FunC/Tolk. + * + * This function: + * 1. Takes a path to the original `.fif` assembly file (with actual names) + * 2. Combines it with a modified version of `Asm.fif` that outputs function names and hashes + * 3. Runs Fift compilation to get the `HASH -> name` mapping from stdout + * 4. Returns a Map that can be used by `AssemblyWriter.write()` to restore original names + * + * @param path Path to the original `.fif` assembly file + * @returns Map of function hashes to their original names + */ +export async function obtainSourceMap(path: string): Promise { + const content = readFileSync(path).toString() + const result = await compileFiftForSourceMap(content) + return result.sourceMap +} diff --git a/src/fift/AsmWithDebugInfo.fif b/src/fift/AsmWithDebugInfo.fif new file mode 100644 index 0000000..c25650b --- /dev/null +++ b/src/fift/AsmWithDebugInfo.fif @@ -0,0 +1,2275 @@ +library TVM_Asm +// simple TVM Assembler +namespace Asm +Asm definitions +"0.4.5" constant asm-fif-version + +variable @atend +variable @was-split +false @was-split ! +{ "not in asm context" abort } @atend ! +{ `normal eq? not abort"must be terminated by }>" } : @normal? +{ context@ @atend @ 2 { @atend ! context! @normal? } does @atend ! } : @pushatend +{ @pushatend Asm +{ }> b> } : }>c +{ }>c s +{ @atend @ 2 { true @was-split ! @atend ! rot b> ref, swap @endblk } does @atend ! = -rot <= and } : 2x<= +{ 2 pick brembitrefs 1- 2x<= } : @havebitrefs +{ @havebits ' @| ifnot } : @ensurebits +{ @havebitrefs ' @| ifnot } : @ensurebitrefs +{ rot over @ensurebits -rot u, } : @simpleuop +{ tuck sbitrefs @ensurebitrefs swap s, } : @addop +{ tuck bbitrefs @ensurebitrefs swap b+ } : @addopb +' @addopb : @inline +{ 1 ' @addop does create } : @Defop +{ 1 { } : si() +// x mi ma -- ? +{ rot tuck >= -rot <= and } : @range +{ rot tuck < -rot > or } : @-range +{ @-range abort"Out of range" } : @rangechk +{ dup 0 < over 255 > or abort"Invalid stack register number" si() } : s() +{ si() constant } : @Sreg +-2 @Sreg s(-2) +-1 @Sreg s(-1) +0 @Sreg s0 +1 @Sreg s1 +2 @Sreg s2 +3 @Sreg s3 +4 @Sreg s4 +5 @Sreg s5 +6 @Sreg s6 +7 @Sreg s7 +8 @Sreg s8 +9 @Sreg s9 +10 @Sreg s10 +11 @Sreg s11 +12 @Sreg s12 +13 @Sreg s13 +14 @Sreg s14 +15 @Sreg s15 +{ dup 0 < over 7 > or abort"Invalid control register number" } : c() +{ c() constant } : @Creg +0 @Creg c0 +1 @Creg c1 +2 @Creg c2 +3 @Creg c3 +4 @Creg c4 +5 @Creg c5 +7 @Creg c7 +{ abort"not a stack register" 12 i@+ s> } : @bigsridx +{ @bigsridx dup 16 >= over 0< or abort"stack register s0..s15 expected" } : @sridx +{ rot @bigsridx tuck < -rot tuck > rot or abort"stack register out of range" } : @sridxrange +{ swap @bigsridx + dup 16 >= over 0< or abort"stack register out of range" } : @sridx+ +{ swap 0xcc <> over 7 > or over 6 = or abort"not a control register c0..c5 or c7" } : @cridx +{ = + { tuck 16 >= + { = and + { 15 and abort"integer too large" 8 + 2dup fits } until + > 2- 5 u, -rot i, + } cond + } cond + } cond + @addopb } dup : PUSHINT : INT +{ dup 256 = abort"use PUSHNAN instead of 256 PUSHPOW2" = or abort"invalid slice padding" + swap 1 1 u, 0 rot u, } : @scomplete +{ tuck sbitrefs swap 26 + swap @havebitrefs not + { PUSHREFSLICE } + { over sbitrefs 2dup 123 0 2x<= + { drop tuck 4 + 3 >> swap x{8B} s, over 4 u, 3 roll s, + -rot 3 << 4 + swap - @scomplete } + { 2dup 1 >= swap 248 <= and + { rot x{8C} s, swap 1- 2 u, over 7 + 3 >> tuck 5 u, 3 roll s, + -rot 3 << 1 + swap - @scomplete } + { rot x{8D} s, swap 3 u, over 2 + 3 >> tuck 7 u, 3 roll s, + -rot 3 << 6 + swap - @scomplete + } cond + } cond + } cond +} dup : PUSHSLICE : SLICE +// ( b' -- ? ) +{ bbitrefs or 0= } : @cont-empty? +{ bbits 7 and 0= } : @cont-aligned? +// ( b b' -- ? ) +{ bbitrefs over 7 and { 2drop drop false } { + swap 16 + swap @havebitrefs nip + } cond +} : @cont-fits? +// ( b b' -- ? ) +{ bbitrefs over 7 and { 2drop drop false } { + 32 1 pair+ @havebitrefs nip + } cond +} : @cont-ref-fit? +// ( b b' b'' -- ? ) +{ over @cont-aligned? over @cont-aligned? and not { 2drop drop false } { + bbitrefs rot bbitrefs pair+ swap 32 + swap @havebitrefs nip + } cond +} : @two-cont-fit? +{ 2dup @cont-fits? not + { b> PUSHREFCONT } + { swap over bbitrefs 2dup 120 0 2x<= + { drop swap x{9} s, swap 3 >> 4 u, swap b+ } + { rot x{8F_} s, swap 2 u, swap 3 >> 7 u, swap b+ } cond + } cond +} dup : PUSHCONT : CONT +{ }> PUSHCONT } : }>CONT +{ { @normal? PUSHCONT } @doafter<{ } : CONT:<{ + +// arithmetic operations +{ 2 { rot dup 8 fits + { nip = { rot drop -rot PUSHINT swap LSHIFT# } { + { drop PUSHINT } { + not pow2decomp swap -1 = { nip PUSHPOW2DEC } { + drop PUSHINT + } cond } cond } cond } cond } cond } cond +} dup : PUSHINTX : INTX + +// integer comparison +x{B8} @Defop SGN +x{B9} @Defop LESS +x{BA} @Defop EQUAL +x{BB} @Defop LEQ +x{BC} @Defop GREATER +x{BD} @Defop NEQ +x{BE} @Defop GEQ +x{BF} @Defop CMP +x{C0} x{BA} @Defop(8i,alt) EQINT +x{C000} @Defop ISZERO +x{C1} x{B9} @Defop(8i,alt) LESSINT +{ 1+ LESSINT } : LEQINT +x{C100} @Defop ISNEG +x{C101} @Defop ISNPOS +x{C2} x{BC} @Defop(8i,alt) GTINT +{ 1- GTINT } : GEQINT +x{C200} @Defop ISPOS +x{C2FF} @Defop ISNNEG +x{C3} x{BD} @Defop(8i,alt) NEQINT +x{C300} @Defop ISNZERO +x{C4} @Defop ISNAN +x{C5} @Defop CHKNAN + +// other comparison +x{C700} @Defop SEMPTY +x{C701} @Defop SDEMPTY +x{C702} @Defop SREMPTY +x{C703} @Defop SDFIRST +x{C704} @Defop SDLEXCMP +x{C705} @Defop SDEQ +x{C708} @Defop SDPFX +x{C709} @Defop SDPFXREV +x{C70A} @Defop SDPPFX +x{C70B} @Defop SDPPFXREV +x{C70C} @Defop SDSFX +x{C70D} @Defop SDSFXREV +x{C70E} @Defop SDPSFX +x{C70F} @Defop SDPSFXREV +x{C710} @Defop SDCNTLEAD0 +x{C711} @Defop SDCNTLEAD1 +x{C712} @Defop SDCNTTRAIL0 +x{C713} @Defop SDCNTTRAIL1 + +// cell serialization (Builder manipulation primitives) +x{C8} @Defop NEWC +x{C9} @Defop ENDC +x{CA} @Defop(8u+1) STI +x{CB} @Defop(8u+1) STU +x{CC} @Defop STREF +x{CD} dup @Defop STBREFR @Defop ENDCST +x{CE} @Defop STSLICE +x{CF00} @Defop STIX +x{CF01} @Defop STUX +x{CF02} @Defop STIXR +x{CF03} @Defop STUXR +x{CF04} @Defop STIXQ +x{CF05} @Defop STUXQ +x{CF06} @Defop STIXRQ +x{CF07} @Defop STUXRQ +x{CF08} @Defop(8u+1) STI_l +x{CF09} @Defop(8u+1) STU_l +x{CF0A} @Defop(8u+1) STIR +x{CF0B} @Defop(8u+1) STUR +x{CF0C} @Defop(8u+1) STIQ +x{CF0D} @Defop(8u+1) STUQ +x{CF0E} @Defop(8u+1) STIRQ +x{CF0F} @Defop(8u+1) STURQ +x{CF10} @Defop STREF_l +x{CF11} @Defop STBREF +x{CF12} @Defop STSLICE_l +x{CF13} @Defop STB +x{CF14} @Defop STREFR +x{CF15} @Defop STBREFR_l +x{CF16} @Defop STSLICER +x{CF17} dup @Defop STBR @Defop BCONCAT +x{CF18} @Defop STREFQ +x{CF19} @Defop STBREFQ +x{CF1A} @Defop STSLICEQ +x{CF1B} @Defop STBQ +x{CF1C} @Defop STREFRQ +x{CF1D} @Defop STBREFRQ +x{CF1E} @Defop STSLICERQ +x{CF1F} dup @Defop STBRQ @Defop BCONCATQ +x{CF20} @Defop(ref) STREFCONST +{ > tuck 3 u, 3 roll s, + -rot 3 << 2 + swap - @scomplete } + { 2drop swap PUSHSLICE STSLICER } cond + } cond +} : STSLICECONST +x{CF81} @Defop STZERO +x{CF83} @Defop STONE + +// cell deserialization (CellSlice primitives) +x{D0} @Defop CTOS +x{D1} @Defop ENDS +x{D2} @Defop(8u+1) LDI +x{D3} @Defop(8u+1) LDU +x{D4} @Defop LDREF +x{D5} @Defop LDREFRTOS +x{D6} @Defop(8u+1) LDSLICE +x{D700} @Defop LDIX +x{D701} @Defop LDUX +x{D702} @Defop PLDIX +x{D703} @Defop PLDUX +x{D704} @Defop LDIXQ +x{D705} @Defop LDUXQ +x{D706} @Defop PLDIXQ +x{D707} @Defop PLDUXQ +x{D708} @Defop(8u+1) LDI_l +x{D709} @Defop(8u+1) LDU_l +x{D70A} @Defop(8u+1) PLDI +x{D70B} @Defop(8u+1) PLDU +x{D70C} @Defop(8u+1) LDIQ +x{D70D} @Defop(8u+1) LDUQ +x{D70E} @Defop(8u+1) PLDIQ +x{D70F} @Defop(8u+1) PLDUQ +{ dup 31 and abort"argument must be a multiple of 32" 5 >> 1- + > swap x{D72A_} s, over 7 u, 3 roll s, + -rot 3 << 3 + swap - @scomplete } : SDBEGINS:imm +{ tuck sbitrefs abort"no references allowed in slice" dup 26 <= + { drop > swap x{D72E_} s, over 7 u, 3 roll s, + -rot 3 << 3 + swap - @scomplete } : SDBEGINSQ:imm +{ tuck sbitrefs abort"no references allowed in slice" dup 26 <= + { drop rot 2 } { + swap @| swap 2dup @cont-fits? { rot 1 } { + b> rot 2 + } cond } cond } cond } cond + [] execute +} : @run-cont-op +{ triple 1 ' @run-cont-op does create } : @def-cont-op +{ DROP } { PUSHCONT IF } { IFREF } @def-cont-op IF-cont +{ IFRET } { PUSHCONT IFJMP } { IFJMPREF } @def-cont-op IFJMP-cont +{ DROP } { PUSHCONT IFNOT } { IFNOTREF } @def-cont-op IFNOT-cont +{ IFNOTRET } { PUSHCONT IFNOTJMP } { IFNOTJMPREF } @def-cont-op IFNOTJMP-cont +{ dup 2over rot } : 3dup + +recursive IFELSE-cont2 { + dup @cont-empty? { drop IF-cont } { + over @cont-empty? { nip IFNOT-cont } { + 3dup @two-cont-fit? { -rot PUSHCONT swap PUSHCONT IFELSE } { + 3dup nip @cont-ref-fit? { rot swap PUSHCONT swap b> IFREFELSE } { + 3dup drop @cont-ref-fit? { -rot PUSHCONT swap b> IFELSEREF } { + rot 32 2 @havebitrefs { rot b> rot b> IFREFELSEREF } { + @| -rot IFELSE-cont2 + } cond } cond } cond } cond } cond } cond +} swap ! + +{ }> IF-cont } : }>IF +{ }> IFNOT-cont } : }>IFNOT +{ }> IFJMP-cont } : }>IFJMP +{ }> IFNOTJMP-cont } : }>IFNOTJMP +{ { @normal? IFJMP-cont } @doafter<{ } : IFJMP:<{ +{ { @normal? IFNOTJMP-cont } @doafter<{ } : IFNOTJMP:<{ +{ `else @endblk } : }>ELSE<{ +{ `else: @endblk } : }>ELSE: +{ 1 { swap @normal? swap IFELSE-cont2 } does @doafter<{ } : @doifelse +{ 1 { swap @normal? IFELSE-cont2 } does @doafter<{ } : @doifnotelse +{ + { dup `else eq? + { drop @doifelse } + { dup `else: eq? + { drop IFJMP-cont } + { @normal? IF-cont + } cond + } cond + } @doafter<{ +} : IF:<{ +{ + { dup `else eq? + { drop @doifnotelse } + { dup `else: eq? + { drop IFNOTJMP-cont } + { @normal? IFNOT-cont + } cond + } cond + } @doafter<{ +} : IFNOT:<{ + +x{E304} @Defop CONDSEL +x{E305} @Defop CONDSELCHK +x{E308} @Defop IFRETALT +x{E309} @Defop IFNOTRETALT +{ DO<{ +{ `do: @endblk } : }>DO: +{ }> PUSHCONT REPEAT } : }>REPEAT +{ { @normal? PUSHCONT REPEAT } @doafter<{ } : REPEAT:<{ +{ }> PUSHCONT UNTIL } : }>UNTIL +{ { @normal? PUSHCONT UNTIL } @doafter<{ } : UNTIL:<{ +{ PUSHCONT { @normal? PUSHCONT WHILE } @doafter<{ } : @dowhile +{ + { dup `do eq? + { drop @dowhile } + { `do: eq? not abort"`}>DO<{` expected" PUSHCONT WHILEEND + } cond + } @doafter<{ +} : WHILE:<{ +{ }> PUSHCONT AGAIN } : }>AGAIN +{ { @normal? PUSHCONT AGAIN } @doafter<{ } : AGAIN:<{ + +x{E314} @Defop REPEATBRK +x{E315} @Defop REPEATENDBRK +x{E316} @Defop UNTILBRK +x{E317} dup @Defop UNTILENDBRK @Defop UNTILBRK: +x{E318} @Defop WHILEBRK +x{E319} @Defop WHILEENDBRK +x{E31A} @Defop AGAINBRK +x{E31B} dup @Defop AGAINENDBRK @Defop AGAINBRK: + +{ }> PUSHCONT REPEATBRK } : }>REPEATBRK +{ { @normal? PUSHCONT REPEATBRK } @doafter<{ } : REPEATBRK:<{ +{ }> PUSHCONT UNTILBRK } : }>UNTILBRK +{ { @normal? PUSHCONT UNTILBRK } @doafter<{ } : UNTILBRK:<{ +{ PUSHCONT { @normal? PUSHCONT WHILEBRK } @doafter<{ } : @dowhile +{ + { dup `do eq? + { drop @dowhile } + { `do: eq? not abort"`}>DO<{` expected" PUSHCONT WHILEENDBRK + } cond + } @doafter<{ +} : WHILEBRK:<{ +{ }> PUSHCONT AGAINBRK } : }>AGAINBRK +{ { @normal? PUSHCONT AGAINBRK } @doafter<{ } : AGAINBRK:<{ + + +// +// continuation stack manipulation and continuation creation +// +{ PUSHCONT ATEXIT } : }>ATEXIT +{ { @normal? PUSHCONT ATEXIT } @doafter<{ } : ATEXIT:<{ +x{EDF4} @Defop ATEXITALT +{ }> PUSHCONT ATEXITALT } : }>ATEXITALT +{ { @normal? PUSHCONT ATEXITALT } @doafter<{ } : ATEXITALT:<{ +x{EDF5} @Defop SETEXITALT +{ }> PUSHCONT SETEXITALT } : }>SETEXITALT +{ { @normal? PUSHCONT SETEXITALT } @doafter<{ } : SETEXITALT:<{ +x{EDF6} @Defop THENRET +x{EDF7} @Defop THENRETALT +x{EDF8} @Defop INVERT +x{EDF9} @Defop BOOLEVAL +x{EDFA} @Defop SAMEALT +x{EDFB} @Defop SAMEALTSAVE +// x{EE} is BLESSARGS +// +// dictionary subroutine call/jump primitives +{ c3 PUSH EXECUTE } : CALLVAR +{ c3 PUSH JMPX } : JMPVAR +{ c3 PUSH } : PREPAREVAR +{ dup 14 ufits { + dup 8 ufits { + CATCH<{ +{ PUSHCONT { @normal? PUSHCONT TRY } @doafter<{ } : @trycatch +{ + { `catch eq? not abort"`}>CATCH<{` expected" @trycatch + } @doafter<{ +} : TRY:<{ +// +// dictionary manipulation +' NULL : NEWDICT +' ISNULL : DICTEMPTY +' STSLICE : STDICTS +x{F400} dup @Defop STDICT @Defop STOPTREF +x{F401} dup @Defop SKIPDICT @Defop SKIPOPTREF +x{F402} @Defop LDDICTS +x{F403} @Defop PLDDICTS +x{F404} dup @Defop LDDICT @Defop LDOPTREF +x{F405} dup @Defop PLDDICT @Defop PLDOPTREF +x{F406} @Defop LDDICTQ +x{F407} @Defop PLDDICTQ + +x{F40A} @Defop DICTGET +x{F40B} @Defop DICTGETREF +x{F40C} @Defop DICTIGET +x{F40D} @Defop DICTIGETREF +x{F40E} @Defop DICTUGET +x{F40F} @Defop DICTUGETREF + +x{F412} @Defop DICTSET +x{F413} @Defop DICTSETREF +x{F414} @Defop DICTISET +x{F415} @Defop DICTISETREF +x{F416} @Defop DICTUSET +x{F417} @Defop DICTUSETREF +x{F41A} @Defop DICTSETGET +x{F41B} @Defop DICTSETGETREF +x{F41C} @Defop DICTISETGET +x{F41D} @Defop DICTISETGETREF +x{F41E} @Defop DICTUSETGET +x{F41F} @Defop DICTUSETGETREF + +x{F422} @Defop DICTREPLACE +x{F423} @Defop DICTREPLACEREF +x{F424} @Defop DICTIREPLACE +x{F425} @Defop DICTIREPLACEREF +x{F426} @Defop DICTUREPLACE +x{F427} @Defop DICTUREPLACEREF +x{F42A} @Defop DICTREPLACEGET +x{F42B} @Defop DICTREPLACEGETREF +x{F42C} @Defop DICTIREPLACEGET +x{F42D} @Defop DICTIREPLACEGETREF +x{F42E} @Defop DICTUREPLACEGET +x{F42F} @Defop DICTUREPLACEGETREF + +x{F432} @Defop DICTADD +x{F433} @Defop DICTADDREF +x{F434} @Defop DICTIADD +x{F435} @Defop DICTIADDREF +x{F436} @Defop DICTUADD +x{F437} @Defop DICTUADDREF +x{F43A} @Defop DICTADDGET +x{F43B} @Defop DICTADDGETREF +x{F43C} @Defop DICTIADDGET +x{F43D} @Defop DICTIADDGETREF +x{F43E} @Defop DICTUADDGET +x{F43F} @Defop DICTUADDGETREF + +x{F441} @Defop DICTSETB +x{F442} @Defop DICTISETB +x{F443} @Defop DICTUSETB +x{F445} @Defop DICTSETGETB +x{F446} @Defop DICTISETGETB +x{F447} @Defop DICTUSETGETB + +x{F449} @Defop DICTREPLACEB +x{F44A} @Defop DICTIREPLACEB +x{F44B} @Defop DICTUREPLACEB +x{F44D} @Defop DICTREPLACEGETB +x{F44E} @Defop DICTIREPLACEGETB +x{F44F} @Defop DICTUREPLACEGETB + +x{F451} @Defop DICTADDB +x{F452} @Defop DICTIADDB +x{F453} @Defop DICTUADDB +x{F455} @Defop DICTADDGETB +x{F456} @Defop DICTIADDGETB +x{F457} @Defop DICTUADDGETB + +x{F459} @Defop DICTDEL +x{F45A} @Defop DICTIDEL +x{F45B} @Defop DICTUDEL + +x{F462} @Defop DICTDELGET +x{F463} @Defop DICTDELGETREF +x{F464} @Defop DICTIDELGET +x{F465} @Defop DICTIDELGETREF +x{F466} @Defop DICTUDELGET +x{F467} @Defop DICTUDELGETREF + +x{F469} @Defop DICTGETOPTREF +x{F46A} @Defop DICTIGETOPTREF +x{F46B} @Defop DICTUGETOPTREF +x{F46D} @Defop DICTSETGETOPTREF +x{F46E} @Defop DICTISETGETOPTREF +x{F46F} @Defop DICTUSETGETOPTREF + +x{F470} @Defop PFXDICTSET +x{F471} @Defop PFXDICTREPLACE +x{F472} @Defop PFXDICTADD +x{F473} @Defop PFXDICTDEL + +x{F474} @Defop DICTGETNEXT +x{F475} @Defop DICTGETNEXTEQ +x{F476} @Defop DICTGETPREV +x{F477} @Defop DICTGETPREVEQ +x{F478} @Defop DICTIGETNEXT +x{F479} @Defop DICTIGETNEXTEQ +x{F47A} @Defop DICTIGETPREV +x{F47B} @Defop DICTIGETPREVEQ +x{F47C} @Defop DICTUGETNEXT +x{F47D} @Defop DICTUGETNEXTEQ +x{F47E} @Defop DICTUGETPREV +x{F47F} @Defop DICTUGETPREVEQ + +x{F482} @Defop DICTMIN +x{F483} @Defop DICTMINREF +x{F484} @Defop DICTIMIN +x{F485} @Defop DICTIMINREF +x{F486} @Defop DICTUMIN +x{F487} @Defop DICTUMINREF +x{F48A} @Defop DICTMAX +x{F48B} @Defop DICTMAXREF +x{F48C} @Defop DICTIMAX +x{F48D} @Defop DICTIMAXREF +x{F48E} @Defop DICTUMAX +x{F48F} @Defop DICTUMAXREF + +x{F492} @Defop DICTREMMIN +x{F493} @Defop DICTREMMINREF +x{F494} @Defop DICTIREMMIN +x{F495} @Defop DICTIREMMINREF +x{F496} @Defop DICTUREMMIN +x{F497} @Defop DICTUREMMINREF +x{F49A} @Defop DICTREMMAX +x{F49B} @Defop DICTREMMAXREF +x{F49C} @Defop DICTIREMMAX +x{F49D} @Defop DICTIREMMAXREF +x{F49E} @Defop DICTUREMMAX +x{F49F} @Defop DICTUREMMAXREF + +x{F4A0} @Defop DICTIGETJMP +x{F4A1} @Defop DICTUGETJMP +x{F4A2} @Defop DICTIGETEXEC +x{F4A3} @Defop DICTUGETEXEC +{ dup sbitrefs tuck 1 > swap 1 <> or abort"not a dictionary" swap 1 u@ over <> abort"not a dictionary" } : @chkdicts +{ dup null? tuck { idict! drop @procmapdict ! } : @procmapadd +{ swap $>s swap @globvardict @ 32 idict! drop @globvardict ! } : @globvaradd +{ pair @proclist @ cons @proclist ! } : @proclistadd +{ @procinfo @ @procdictkeylen idict@ { 16 i@ } { 0 } cond } : @procinfo@ +{ idict! + not abort"cannot add key to procedure info dictionary" + @procinfo ! +} : @procinfo! +// ( x v1 v2 -- ) +{ not 2 pick @procinfo@ and xor swap @procinfo! } : @procinfo~! +// ( s i f -- ) +{ over @procdictkeylen fits not abort"procedure index out of range" + over swap dup @procinfo~! 2dup @proclistadd + 1 'nop does swap 0 (create) +} : @declproc +{ 2dup @globvaradd 1 'nop does swap 0 (create) } : @declglobvar +{ @proccnt @ 1+ dup @proccnt ! 1 @declproc } : @newproc +{ @gvarcnt @ 1+ dup @gvarcnt ! @declglobvar } : @newglobvar +variable @oldcurrent variable @oldctx +Fift-wordlist dup @oldcurrent ! @oldctx ! +{ current@ @oldcurrent ! context@ @oldctx ! Asm definitions + @proccnt @ @proclist @ @procdict @ @procinfo @ @gvarcnt @ @parent-state @ current@ @oldcurrent @ @oldctx @ + 9 tuple @parent-state ! + hole current! + 0 =: main @proclist null! @proccnt 0! @gvarcnt 0! + { bl word @newproc } : NEWPROC + { bl word dup (def?) ' drop ' @newproc cond } : DECLPROC + { bl word dup find + { nip execute <> abort"method redefined with different id" } + { swap 17 @declproc } + cond } : DECLMETHOD + { bl word @newglobvar } : DECLGLOBVAR + "main" 0 @proclistadd + dictnew dup @procdict ! + @procinfo ! 16 0 @procinfo! +} : PROGRAM{ +{ over sbits < { s>c c } { dup srefs { ref@ } { s>c } cond } cond hashu dup . B B, // code_hash + method_name + 2 pick // method_id + @procmapadd + + swap 2dup @procinfo@ @chkprocdef (forget) + } while + + drop @proclist null! @procinfo null! @proccnt 0! + @procdict dup @ swap null! + @parent-state @ dup null? { drop } { + 9 untuple + @oldctx ! @oldcurrent ! current! @parent-state ! @gvarcnt ! @procinfo ! @procdict ! @proclist ! @proccnt ! + } cond + @oldctx @ context! @oldcurrent @ current! +} : }END +forget @proclist forget @proccnt +{ }END <{ + 76 SETCP + @procmapdict @ ref, + @globvardict @ dict, +}> } : }END> +{ }END> b> } : }END>c +{ }END>c s + +// This is the way how FunC assigns method_id for reserved functions. +// Note, that Tolk entrypoints have other names (`onInternalMessage`, etc.), +// but method_id is assigned not by Fift, but by Tolk code generation. +0 constant recv_internal +-1 constant recv_external +-2 constant run_ticktock +-3 constant split_prepare +-4 constant split_install + +{ asm-mode 0 3 ~! } : asm-no-remove-unused +{ asm-mode 1 1 ~! } : asm-remove-unused // enabled by default +{ asm-mode 3 3 ~! } : asm-warn-remove-unused +{ asm-mode 4 4 ~! } : asm-warn-inline-mix +{ asm-mode 0 4 ~! } : asm-no-warn-inline-mix // disabled by default +{ asm-mode 8 8 ~! } : asm-warn-unused +{ asm-mode 0 8 ~! } : asm-no-warn-unused // disabled by default + +// ( c -- ) add vm library for later use with runvmcode +{ spec } : hash>libref +// ( c -- c' ) +{ hash hash>libref } : >libref + +{ dup "." $pos dup -1 = + { drop 0 } + { $| 1 $| nip swap (number) 1- abort"invalid version" + dup dup 0 < swap 999 > or abort"invalid version" + } + cond +} : parse-version-level + +{ + 0 swap + "." $+ + { swap 1000 * swap parse-version-level rot + swap } 3 times + "" $= not abort"invalid version" +} : parse-asm-fif-version + +{ + dup =: required-version parse-asm-fif-version + asm-fif-version parse-asm-fif-version + = 1+ { + "Required Asm.fif version: " @' required-version "; actual Asm.fif version: " asm-fif-version $+ $+ $+ abort + } if +} : require-asm-fif-version + +{ + dup =: required-version parse-asm-fif-version + asm-fif-version parse-asm-fif-version + swap + >= 1+ { + "Required Asm.fif version: " @' required-version "; actual Asm.fif version: " asm-fif-version $+ $+ $+ abort + } if +} : require-asm-fif-version>= + + +Fift definitions Asm +' <{ : <{ +' PROGRAM{ : PROGRAM{ +' asm-fif-version : asm-fif-version +' require-asm-fif-version : require-asm-fif-version +' require-asm-fif-version>= : require-asm-fif-version>= +Fift +library TonUtil // TON Blockchain Fift Library + +library Lists // List utilities +// +{ hole dup 1 { @ execute } does create } : recursive +// x x' -- ? recursively compares two S-expressions +recursive equal? { + dup tuple? { + over tuple? { + over count over count over = { // t t' l ? + 0 { dup 0>= { 2dup [] 3 pick 2 pick [] equal? { 1+ } { drop -1 } cond + } if } rot times + nip nip 0>= + } { drop 2drop false } cond + } { 2drop false } cond + } { eqv? } cond +} swap ! +// (a1 .. an) -- (an .. a1) +{ null swap { dup null? not } { uncons swap rot cons swap } while drop } : list-reverse +// (a1 .. an) -- an Computes last element of non-empty list l +{ { uncons dup null? { drop true } { nip false } cond } until } : list-last +// l l' -- l++l' Concatenates two lists +recursive list+ { + over null? { nip } { swap uncons rot list+ cons } cond +} swap ! +// l l' -- l'' -1 or 0, where l = l' ++ l'' +// Removes prefix from list +{ { dup null? { drop true true } { + swap dup null? { 2drop false true } { // l' l + uncons swap rot uncons -rot equal? { false } { + 2drop false true + } cond } cond } cond } until +} : list- +// (a1 .. an) -- a1 .. an n Explodes a list +{ 0 { over null? not } { swap uncons rot 1+ } while nip } : explode-list +// (a1 .. an) x -- a1 .. an n x Explodes a list under the topmost element +{ swap explode-list dup 1+ roll } : explode-list-1 +// l -- t Transforms a list into a tuple with the same elements +{ explode-list tuple } : list>tuple +// a1 ... an n x -- (a1 .. an) x +{ null swap rot { -rot cons swap } swap times } : mklist-1 +// (s1 ... sn) -- s1+...+sn Concatenates a list of strings +{ "" { over null? not } { swap uncons -rot $+ } while nip +} : concat-string-list +// (x1 ... xn) -- x1+...+xn Sums a list of integers +{ 0 { over null? not } { swap uncons -rot + } while nip +} : sum-list +// (a1 ... an) a e -- e(...e(e(a,a1),a2),...),an) +{ -rot { over null? not } { swap uncons -rot 3 pick execute } while nip nip +} : foldl +// (a1 ... an) e -- e(...e(e(a1,a2),a3),...),an) +{ swap uncons swap rot foldl } : foldl-ne +// (a1 ... an) a e -- e(a1,e(a2,...,e(an,a)...)) +recursive foldr { + rot dup null? { 2drop } { + uncons -rot 2swap swap 3 pick foldr rot execute + } cond +} swap ! +// (a1 ... an) e -- e(a1,e(a2,...,e(a[n-1],an)...)) +recursive foldr-ne { + over cdr null? { drop car } { + swap uncons 2 pick foldr-ne rot execute + } cond +} swap ! +// (l1 ... ln) -- l1++...++ln Concatenates a list of lists +{ dup null? { ' list+ foldr-ne } ifnot } : concat-list-lists +// (a1 .. an . t) n -- t Computes the n-th tail of a list +{ ' cdr swap times } : list-tail +// (a0 .. an ..) n -- an Computes the n-th element of a list +{ list-tail car } : list-ref +// l -- ? +{ { dup null? { drop true true } { + dup pair? { cdr false } { + drop false true + } cond } cond } until +} : list? +// l -- n +{ 0 { over null? not } { 1+ swap uncons nip swap } while nip +} : list-length +// l e -- t // returns tail of l after first member that satisfies e +{ swap { + dup null? { nip true } { + tuck car over execute { drop true } { + swap cdr false + } cond } cond } until +} : list-tail-from +// a l -- t // tail of l after first occurence of a using eq? +{ swap 1 ' eq? does list-tail-from } : list-member-eq +{ swap 1 ' eqv? does list-tail-from } : list-member-eqv +{ swap 1 ' equal? does list-tail-from } : list-member-equal +// a l -- ? +{ list-member-eq null? not } : list-member? +{ list-member-eqv null? not } : list-member-eqv? +// l -- a -1 or 0 // returns car l if l is non-empty +{ dup null? { drop false } { car true } cond +} : safe-car +{ dup null? { drop false } { car second true } cond +} : get-first-value +// l e -- v -1 or 0 +{ list-tail-from safe-car } : assoc-gen +{ list-tail-from get-first-value } : assoc-gen-x +// a l -- (a.v) -1 or 0 -- returns first entry (a . v) in l +{ swap 1 { swap first eq? } does assoc-gen } : assq +{ swap 1 { swap first eqv? } does assoc-gen } : assv +{ swap 1 { swap first equal? } does assoc-gen } : assoc +// a l -- v -1 or 0 -- returns v from first entry (a . v) in l +{ swap 1 { swap first eq? } does assoc-gen-x } : assq-val +{ swap 1 { swap first eqv? } does assoc-gen-x } : assv-val +{ swap 1 { swap first equal? } does assoc-gen-x } : assoc-val +// (a1 .. an) e -- (e(a1) .. e(an)) +recursive list-map { + over null? { drop } { + swap uncons -rot over execute -rot list-map cons + } cond +} swap ! + +variable ctxdump variable curctx +// (a1 .. an) e -- executes e for a1, ..., an +{ ctxdump @ curctx @ ctxdump 2! curctx 2! + { curctx 2@ over null? not } { swap uncons rot tuck curctx 2! execute } + while 2drop ctxdump 2@ curctx ! ctxdump ! +} : list-foreach +forget ctxdump forget curctx + +// +// Experimental implementation of `for` loops with index +// +variable loopdump variable curloop +{ curloop @ loopdump @ loopdump 2! } : push-loop-ctx +{ loopdump 2@ loopdump ! curloop ! } : pop-loop-ctx +// ilast i0 e -- executes e for i=i0,i0+1,...,ilast-1 +{ -rot 2dup > { + push-loop-ctx { + triple dup curloop ! first execute curloop @ untriple 1+ 2dup <= + } until pop-loop-ctx + } if 2drop drop +} : for +// ilast i0 e -- same as 'for', but pushes current index i before executing e +{ -rot 2dup > { + push-loop-ctx { + triple dup curloop ! untriple nip swap execute curloop @ untriple 1+ 2dup <= + } until pop-loop-ctx + } if 2drop drop +} : for-i +// ( -- i ) Returns innermost loop index +{ curloop @ third } : i +// ( -- j ) Returns outer loop index +{ loopdump @ car third } : j +{ loopdump @ cadr third } : k +forget curloop forget loopdump + +// +// create Lisp-style lists using words "(" and ")" +// +variable ') +'nop box constant ', +{ ") without (" abort } ') ! +{ ') @ execute } : ) +anon constant dot-marker +// m x1 ... xn t m -- (x1 ... xn . t) +{ swap + { -rot 2dup eq? not } + { over dot-marker eq? abort"invalid dotted list" + swap rot cons } while 2drop +} : list-tail-until-marker +// m x1 ... xn m -- (x1 ... xn) +{ null swap list-tail-until-marker } : list-until-marker +{ over dot-marker eq? { nip 2dup eq? abort"invalid dotted list" } + { null swap } cond + list-tail-until-marker +} : list-until-marker-ext +{ ') @ ', @ } : ops-get +{ ', ! ') ! } : ops-set +{ anon dup ops-get 3 { ops-set list-until-marker-ext } does ') ! 'nop ', ! +} : ( +// test of Lisp-style lists +// ( 42 ( `+ 9 ( `* 3 4 ) ) "test" ) .l cr +// ( `eq? ( `* 3 4 ) 3 4 * ) .l cr +// `alpha ( `beta `gamma `delta ) cons .l cr +// { ( `eq? ( `* 3 5 pick ) 3 4 roll * ) } : 3*sample +// 17 3*sample .l cr + +// similar syntax _( x1 .. xn ) for tuples +{ 2 { 1+ 2dup pick eq? } until 3 - nip } : count-to-marker +{ count-to-marker tuple nip } : tuple-until-marker +{ anon dup ops-get 3 { ops-set tuple-until-marker } does ') ! 'nop ', ! } : _( +// test of tuples +// _( _( 2 "two" ) _( 3 "three" ) _( 4 "four" ) ) .dump cr + +// pseudo-Lisp tokenizer +"()[]'" 34 hold constant lisp-delims +{ lisp-delims 11 (word) } : lisp-token +{ null cons `quote swap cons } : do-quote +{ 1 { ', @ 2 { 2 { ', ! execute ', @ execute } does ', ! } + does ', ! } does +} : postpone-prefix +{ ', @ 1 { ', ! } does ', ! } : postpone-', +( `( ' ( pair + `) ' ) pair + `[ ' _( pair + `] ' ) pair + `' ' do-quote postpone-prefix pair + `. ' dot-marker postpone-prefix pair + `" { char " word } pair + `;; { 0 word drop postpone-', } pair +) constant lisp-token-dict +variable eol +{ eol @ eol 0! anon dup ') @ 'nop 3 + { ops-set list-until-marker-ext true eol ! } does ') ! rot ', ! + { lisp-token dup (number) dup { roll drop } { + drop atom dup lisp-token-dict assq { nip second execute } if + } cond + ', @ execute + eol @ + } until + -rot eol ! execute +} :_ List-generic( +{ 'nop 'nop List-generic( } :_ LIST( +// LIST((lambda (x) (+ x 1)) (* 3 4)) +// LIST('(+ 3 4)) +// LIST(2 3 "test" . 9) +// LIST((process '[plus 3 4])) + + +-1 constant Masterchain +0 constant Basechain + +// parse workchain id +// ( S -- workchain ) +{ (number) 1- abort"workchain id must be an integer" + dup 32 fits not abort"workchain id must fit in 32 bits" +} : parse-workchain-id + +{ (number) 1- abort"integer expected" } : parse-int + +{ over null? ' swap if drop } : replace-if-null + +// Private key load/generate +// ( fname -- pubkey privkey ) +{ dup ."Loading private key from file " type cr + file>B dup Blen 32 <> abort"Private key must be exactly 32 bytes long" + dup priv>pub swap +} : load-keypair +// ( fname -- pubkey privkey ) +{ dup file-exists? + { load-keypair } + { dup newkeypair swap rot over swap B>file + rot ."Saved new private key to file " type cr + } cond +} : load-generate-keypair + +// Parse smart-contract address +// ( S -- workchain addr bounce? ) +{ $>smca not abort"invalid smart-contract address" + 1 and 0= +} : parse-smc-addr + +// ( x -- ) Displays a 64-digit hex number +{ 64 0x. } : 64x. +{ 64 0X. } : 64X. +// ( wc addr -- ) Show address in : form +{ swap ._ .":" 64x. } : .addr +// ( wc addr flags -- ) Show address in base64url form +{ smca>$ type } : .Addr +// ( wc addr fname -- ) Save address to file in 36-byte format +{ -rot 256 u>B swap 32 i>B B+ swap B>file } : save-address +// ( wc addr fname -- ) Save address and print message +{ dup ."(Saving address to file " type .")" cr save-address +} : save-address-verbose + +// ( fname -- wc addr ) Load address from file +{ file>B 32 B| + dup Blen { 32 B>i@ } { drop Basechain } cond + swap 256 B>u@ +} : load-address +// ( fname -- wc addr ) Load address from file and print message +{ dup ."(Loading address from file " type .")" cr load-address +} : load-address-verbose +// Parse string as address or load address from file (if string is prefixed by @) +// ( S default-bounce -- workchain addr bounce? ) +{ over $len 0= abort"empty smart-contract address" + swap dup 1 $| swap "@" $= + { nip load-address rot } { drop nip parse-smc-addr } cond +} : parse-load-address + +// ( hex-str -- addr ) Parses ADNL address +{ dup $len 64 <> abort"ADNL address must consist of exactly 64 hexadecimal characters" + (hex-number) 1 <> abort"ADNL address must consist of 64 hexadecimal characters" + dup 256 ufits not abort"invalid ADNL address" +} : parse-adnl-address + +// ( b wc addr -- b' ) Serializes address into Builder b +{ -rot 8 i, swap 256 u, } : addr, +{ over 8 fits { rot b{100} s, -rot addr, } { + rot b{110} s, 256 9 u, rot 32 i, swap 256 u, } cond +} : Addr, + +// Gram utilities +1000000000 constant Gram +{ Gram swap */r } : Gram*/ +{ Gram * } : Gram* +{ (number) dup { 1- ' Gram*/ ' Gram* cond true } if +} : $>GR? +// ( S -- nanograms ) +{ $>GR? not abort"not a valid Gram amount" +} : $>GR +{ bl word $>GR 1 'nop } ::_ GR$ +// ( nanograms -- S ) +{ dup abs <# ' # 9 times char . hold #s rot sign #> +nip -trailing0 } : (.GR) +{ (.GR) ."GR$" type } : .GR_ +{ .GR_ space } : .GR + +// b x -- b' ( serializes a Gram amount ) +{ -1 { 1+ 2dup 8 * ufits } until + rot over 4 u, -rot 8 * u, } : Gram, +// s -- x s' ( deserializes a Gram amount ) +{ 4 u@+ swap 8 * u@+ } : Gram@+ +// s -- x +{ 4 u@+ swap 8 * u@ } : Gram@ + +// currency collections +// b x --> b' ( serializes a VarUInteger32 ) +{ -1 { 1+ 2dup 8 * ufits } until + rot over 5 u, -rot 8 * u, } : VarUInt32, +// s --> x ( deserializes a VarUInteger32 ) +{ 5 u@+ swap 8 * u@ } : VarUInt32@ +32 constant cc-key-bits +' VarUInt32, : val, +' VarUInt32@ : val@ +// d k v -- d' +{ cc +{ dup null? { ."(null)" drop } { val@ ._ } cond } dup : .maybeVarUInt32 : .val +{ swap cc-key-bits { rot { ."+" } if .val ."*$" ._ true true } idictforeach drop } : (.cc) +{ false (.cc) { ."0" } ifnot } : .cc_ +{ .cc_ space } : .cc +{ true (.cc) drop } : .+cc_ +{ .+cc_ space } : .+cc +{ cc-key-bits { rot . ."-> " swap .val .val ."; " true } dictdiff drop cr } : show-cc-diff +{ cc-key-bits { val@ swap val@ + val, true } dictmerge } : cc+ +{ null swap cc-key-bits { val@ pair swap cons true } idictforeach drop } : cc>list-rev +{ cc>list-rev list-reverse } : cc>list +forget val, forget val@ forget .val + +// ( S -- x -1 or 0 ) +{ (number) dup 2 = { -rot 2drop } if 1 = } : int? +{ int? dup { drop dup 0< { drop false } { true } cond } if } : pos-int? +// ( S -- k v -1 or 0 ) Parses expression * or *$ +{ dup "*" $pos dup 0< { 2drop false } { + $| dup $len 2 < { 2drop false } { + 1 $| nip dup 1 $| swap "$" $= { swap } if drop + int? dup { over 32 fits { 2drop false } ifnot } if + not { drop false } { + swap pos-int? not { drop false } { + true + } cond } cond } cond } cond +} : cc-key-value? +// ( S -- D -1 or 0 ) Parses an extra currency collection +// e.g. "10000*$3+7777*$-11" means "10000 units of currency #3 and 7777 units of currency #-11" +{ dictnew { // S D + swap dup "+" $pos dup 0< { drop null -rot } { $| 1 $| nip -rot } cond + cc-key-value? { +ccpair over null? dup { rot drop true } if } { 2drop false true } cond + } until +} : $>xcc? +{ $>xcc? not abort"invalid extra currency collection" } : $>xcc +{ char } word dup $len { $>xcc } { drop dictnew } cond 1 'nop } ::_ CX{ + +// complete currency collections +{ $>xcc? { true } { drop false } cond } : end-parse-cc +// ( S -- x D -1 or 0 ) Parses a currency collection +// e.g. "1.2+300*$2" means "1200000000ng plus 300 units of currency #2" +{ 0 swap dup "+" $pos dup 0< { drop dup + $>GR? { nip nip dictnew true } { end-parse-cc } cond + } { over swap $| swap $>GR? { 2swap 2drop swap 1 $| nip } { drop + } cond end-parse-cc } cond +} : $>cc? +{ $>cc? not abort"invalid currency collection" } : $>cc +{ char } word dup $len { $>cc } { drop 0 dictnew } cond 2 'nop } ::_ CC{ +// ( x D -- ) +{ swap ?dup { .GR_ .+cc_ } { .cc_ } cond } : .GR+cc_ +{ .GR+cc_ space } : .GR+cc +{ -rot Gram, swap dict, } : Gram+cc, + +// Libraries +// ( -- D ) New empty library collection +' dictnew : Libs{ +// ( D -- D ) Return library collection as dictionary +'nop : }Libs +// ( D c x -- D' ) Add a public/private library c to collection D +{ -rot B, swap ref, + } cond +} swap ! +// b S n -- b' +{ swap $>B swap append-long-bytes } : append-long-string +// S -- c +{ +} : simple-transfer-body + +// ( S -- x ) parse public key +{ dup $len 48 <> abort"public key must be 48 characters long" + base64url>B dup Blen 36 <> abort"public key must be 48 characters long" + 34 B| 16 B>u@ over crc16 <> abort"crc16 mismatch in public key" + 16 B>u@+ 0x3ee6 <> abort"invalid tag in public key" + 256 B>u@ +} : parse-pubkey +{ bl word parse-pubkey 1 'nop } ::_ PK' +// ( x -- S ) serialize public key +{ 256 u>B B{3ee6} swap B+ dup crc16 16 u>B B+ B>base64 } : pubkey>$ +{ pubkey>$ type } : .pubkey + +// ( S -- x ) parse validator-encoded public key +{ base64>B dup Blen 36 <> abort"public key with magic must be 36 bytes long" + 4 B| swap 32 B>u@ 0xC6B41348 <> abort"unknown magic for public key (not Ed25519)" +} : parse-val-pubkey +{ bl word parse-val-pubkey 1 'nop } ::_ VPK' +{ char } word base64>B 1 'nop } ::_ B64{ + +// adnl address parser +{ 256 u>B B{2D} swap B+ dup crc16 16 u>B B+ } : adnl-preconv +{ swap 32 /mod dup 26 < { 65 } { 24 } cond + rot swap hold } : Base32# +{ <# ' Base32# 8 times #> } : Base32#*8 +{ "" over Blen 5 / { swap 40 B>u@+ Base32#*8 nip rot swap $+ } swap times nip } : B>Base32 + +// ( x -- S ) Converts an adnl-address from a 256-bit integer to a string +{ adnl-preconv B>Base32 1 $| nip } : adnl>$ + +{ 65 - dup 0>= { -33 and dup 26 < } { 41 + dup 25 > over 32 < and } cond ?dup nip } : Base32-digit? +{ Base32-digit? not abort"not a Base32 digit" } : Base32-digit +{ 0 { over $len } { swap 1 $| -rot (char) Base32-digit swap 5 << + } while nip } : Base32-number +{ B{} { over $len } { swap 8 $| -rot Base32-number 40 u>B B+ } while nip } : Base32>B + +// ( S -- x ) Converts an adnl address from a string to 256-bit integer +{ dup $len 55 <> abort"not 55 alphanumeric characters" "F" swap $+ Base32>B + 33 B| 16 B>u@ over crc16 <> abort"crc16 checksum mismatch" + 8 B>u@+ 0x2D <> abort"not a valid adnl address" 256 B>u@ } : $>adnl + +{ 65 - dup 0>= { -33 and 10 + dup 16 < } { 17 + dup 0>= over 10 < and } cond ?dup nip } : hex-digit? +// ( S -- x -1 or 0 ) Parses a hexadecimal integer +{ dup $len { + 0 { + 4 << swap 1 $| -rot (char) hex-digit? // S a d -1 or S a 0 + { + over $len 0= } { drop -1 true } cond + } until + dup 0< { 2drop false } { nip true } cond + } { drop false } cond +} : hex$>u? +// ( S -- x ) +{ hex$>u? not abort"not a hexadecimal number" } : hex$>u + +{ dup $len 64 = { hex$>u } { + dup $len 55 = { $>adnl } { + true abort"invalid adnl address" + } cond } cond +} : parse-adnl-addr +{ adnl>$ type } : .adnl +{ bl word parse-adnl-addr 1 'nop } ::_ adnl: + +// ( x a b -- a<=x<=b ) +{ 2 pick >= -rot >= and } : in-range? + +// ( c i -- ? ) Checks whether c is a valid value for config param #i +def? config-valid? { + { nip 0>= { ."warning: cannot check validity of configuration parameter value, use create-state instead of fift to check validity" cr } if + true } : config-valid? +} ifnot + +{ dup -1000 = { drop + { + // anycast_info$_ depth:(#<= 30) { depth >= 1 } + // rewrite_pfx:(bits depth) = Anycast; + 30 u@+ swap // get depth + + dup 1 > { + dup 2 roll swap u@+ // get rewrite_pfx + // return depth, rewrite_pfx, slice + } + { + drop // drop depth (<=1) + 0 0 2 roll // set anycast to none + } cond + } + { + 0 0 2 roll // set anycast to none + } cond +} : maybe-anycast + +// Rewrite first bits of addr with anycast info +{ // input: anycast depth, rewrite_pfx, workchain, slice, address length + 4 -roll + 3 roll dup dup 0 = { 2drop 2 roll drop } + { + rot swap u@+ swap drop + 3 roll + // Get addr: addr_none$00 / addr_extern$01 / addr_std$10 / addr_var$11 + { // if greater that zero + dup 1 > + { + 2 = + { + // if addr_std$10 + // anycast:(Maybe Anycast) + // workchain_id:int8 + // address:bits256 = MsgAddressInt; + maybe-anycast // get anycast depth, bits, slice + 8 i@+ // get workchain + 256 parse-address-with-anycast + `addr-std swap + } + + { + // if addr_var$11 + // anycast:(Maybe Anycast) + // addr_len:(## 9) + // workchain_id:int32 + // address:(bits addr_len) = MsgAddressInt; + maybe-anycast // get anycast depth, bits, slice + 9 u@+ // get addr_len + 32 i@+ // get workchain + swap 2 -roll // move workchain to neede position + swap parse-address-with-anycast + `addr-var swap + } cond + + } + { + drop // drop header (dup for statment upper) + // if addr_extern$01 + // addr_extern$01 len:(## 9) + // external_address:(bits len) + 9 u@+ swap // bit len + u@+ // external_address + `addr-extern swap + } cond + } + { + swap + // if addr_none$00 + `addr-none swap + } cond +} : addr@+ + +{ addr@+ drop } : addr@ + +// User-friendly prints output of addr@ +// (0 A or addr A or wc addr A -- ) +{ + dup `addr-none eq? + { 2drop ."addr_none" } + { + `addr-extern eq? + { (dump) type } + { (x.) swap (dump) ":" $+ swap $+ type } + cond + } + cond +} : print-addr // print addr with workchain + +forget maybe-anycast +forget parse-address-with-anycast + +// $1 include diff --git a/src/fift/compileFift.ts b/src/fift/compileFift.ts index a3937ea..1b52bb8 100644 --- a/src/fift/compileFift.ts +++ b/src/fift/compileFift.ts @@ -20,33 +20,55 @@ const writeToCStringPtr = (mod: any, str: string, ptr: any) => { const readFromCString = (mod: any, pointer: Pointer): string => mod.UTF8ToString(pointer) export interface FiftCompilationResultOk { - readonly ok: false + readonly status: "ok" readonly log: string - readonly output: Buffer | null + readonly output: Buffer } export interface FiftCompilationResultError { - readonly ok: true + readonly status: "error" readonly log: string - readonly output: Buffer + readonly output: Buffer | null +} + +export interface FiftCompilationSourceMap { + readonly status: "source_map" + readonly sourceMap: Map } -export type FiftCompilationResult = FiftCompilationResultOk | FiftCompilationResultError +export type FiftCompilationResult = + | FiftCompilationResultOk + | FiftCompilationResultError + | FiftCompilationSourceMap interface CompilationError { readonly status: "error" + readonly codeHashHex: string readonly message: string + readonly output: string } interface CompilationOk { readonly status: "ok" readonly codeBoc: string + readonly codeHashHex: string + readonly message: string readonly warnings: string + readonly output: string } type CompileResult = CompilationError | CompilationOk -export async function compileFift(content: string): Promise { +export async function compileFiftForSourceMap(content: string): Promise { + const result = await compileFift(content, true) + if (result.status !== "source_map") throw new Error("unreachable") + return result +} + +export async function compileFift( + content: string, + generateSourceMap: boolean = false, +): Promise { const allocatedPointers: Pointer[] = [] const allocatedFunctions: Pointer[] = [] @@ -67,6 +89,11 @@ export async function compileFift(content: string): Promise { @@ -85,8 +112,21 @@ export async function compileFift(content: string): Promise 0 ? msg : result.message ? result.message : "Unknown error", output: null, } } return { - ok: true, + status: "ok", log: logs.length > 0 ? msg : result.warnings ? result.warnings : "", output: Buffer.from(result.codeBoc, "base64"), } @@ -119,3 +159,29 @@ export async function compileFift(content: string): Promise { + const tokens = input + .split(/ /g) + .map(t => t.trim()) + .filter(t => t.length > 0) + .map(t => t.replace(/"/g, "")) + + const result = new Map() + + for (let i = 0; i < tokens.length; i += 2) { + if (i + 1 >= tokens.length) break + + const name = tokens[i] + const hash = tokens[i + 1] + + try { + const bigintHash = BigInt(hash) + result.set(bigintHash.toString(16), name) + } catch { + // just skip + } + } + + return result +} diff --git a/src/fift/copy.build.ts b/src/fift/copy.build.ts index 656a171..c66aa48 100644 --- a/src/fift/copy.build.ts +++ b/src/fift/copy.build.ts @@ -13,6 +13,7 @@ const main = async (): Promise => { try { await cp("./src/fift/funcfiftlib.js", "./dist/fift/") await cp("./src/fift/funcfiftlib.wasm", "./dist/fift/") + await cp("./src/fift/AsmWithDebugInfo.fif", "./dist/fift/") } catch (error) { console.error(error) process.exit(1) diff --git a/src/fift/funcfiftlib.js b/src/fift/funcfiftlib.js index ecb27fa..1fd3135 100644 --- a/src/fift/funcfiftlib.js +++ b/src/fift/funcfiftlib.js @@ -426,7 +426,7 @@ var CompilerModule = (() => { Module["asm"] = exports wasmMemory = Module["asm"]["Ja"] updateGlobalBufferAndViews(wasmMemory.buffer) - wasmTable = Module["asm"]["Na"] + wasmTable = Module["asm"]["Oa"] addOnInit(Module["asm"]["Ka"]) removeRunDependency("wasm-instantiate") } @@ -5388,139 +5388,143 @@ var CompilerModule = (() => { var _version = (Module["_version"] = function () { return (_version = Module["_version"] = Module["asm"]["La"]).apply(null, arguments) }) - var _func_compile = (Module["_func_compile"] = function () { - return (_func_compile = Module["_func_compile"] = Module["asm"]["Ma"]).apply( + var _fift_compile = (Module["_fift_compile"] = function () { + return (_fift_compile = Module["_fift_compile"] = Module["asm"]["Ma"]).apply( null, arguments, ) }) + var _fift_compile_anyway = (Module["_fift_compile_anyway"] = function () { + return (_fift_compile_anyway = Module["_fift_compile_anyway"] = + Module["asm"]["Na"]).apply(null, arguments) + }) var _free = (Module["_free"] = function () { - return (_free = Module["_free"] = Module["asm"]["Oa"]).apply(null, arguments) + return (_free = Module["_free"] = Module["asm"]["Pa"]).apply(null, arguments) }) var _malloc = (Module["_malloc"] = function () { - return (_malloc = Module["_malloc"] = Module["asm"]["Pa"]).apply(null, arguments) + return (_malloc = Module["_malloc"] = Module["asm"]["Qa"]).apply(null, arguments) }) var ___errno_location = (Module["___errno_location"] = function () { - return (___errno_location = Module["___errno_location"] = Module["asm"]["Qa"]).apply( + return (___errno_location = Module["___errno_location"] = Module["asm"]["Ra"]).apply( null, arguments, ) }) var _emscripten_builtin_memalign = (Module["_emscripten_builtin_memalign"] = function () { return (_emscripten_builtin_memalign = Module["_emscripten_builtin_memalign"] = - Module["asm"]["Ra"]).apply(null, arguments) + Module["asm"]["Sa"]).apply(null, arguments) }) var _setThrew = (Module["_setThrew"] = function () { - return (_setThrew = Module["_setThrew"] = Module["asm"]["Sa"]).apply(null, arguments) + return (_setThrew = Module["_setThrew"] = Module["asm"]["Ta"]).apply(null, arguments) }) var stackSave = (Module["stackSave"] = function () { - return (stackSave = Module["stackSave"] = Module["asm"]["Ta"]).apply(null, arguments) + return (stackSave = Module["stackSave"] = Module["asm"]["Ua"]).apply(null, arguments) }) var stackRestore = (Module["stackRestore"] = function () { - return (stackRestore = Module["stackRestore"] = Module["asm"]["Ua"]).apply( + return (stackRestore = Module["stackRestore"] = Module["asm"]["Va"]).apply( null, arguments, ) }) var stackAlloc = (Module["stackAlloc"] = function () { - return (stackAlloc = Module["stackAlloc"] = Module["asm"]["Va"]).apply(null, arguments) + return (stackAlloc = Module["stackAlloc"] = Module["asm"]["Wa"]).apply(null, arguments) }) var ___cxa_can_catch = (Module["___cxa_can_catch"] = function () { - return (___cxa_can_catch = Module["___cxa_can_catch"] = Module["asm"]["Wa"]).apply( + return (___cxa_can_catch = Module["___cxa_can_catch"] = Module["asm"]["Xa"]).apply( null, arguments, ) }) var ___cxa_is_pointer_type = (Module["___cxa_is_pointer_type"] = function () { return (___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = - Module["asm"]["Xa"]).apply(null, arguments) + Module["asm"]["Ya"]).apply(null, arguments) }) var dynCall_j = (Module["dynCall_j"] = function () { - return (dynCall_j = Module["dynCall_j"] = Module["asm"]["Ya"]).apply(null, arguments) + return (dynCall_j = Module["dynCall_j"] = Module["asm"]["Za"]).apply(null, arguments) }) var dynCall_viijj = (Module["dynCall_viijj"] = function () { - return (dynCall_viijj = Module["dynCall_viijj"] = Module["asm"]["Za"]).apply( + return (dynCall_viijj = Module["dynCall_viijj"] = Module["asm"]["_a"]).apply( null, arguments, ) }) var dynCall_iij = (Module["dynCall_iij"] = function () { - return (dynCall_iij = Module["dynCall_iij"] = Module["asm"]["_a"]).apply( + return (dynCall_iij = Module["dynCall_iij"] = Module["asm"]["$a"]).apply( null, arguments, ) }) var dynCall_viiijj = (Module["dynCall_viiijj"] = function () { - return (dynCall_viiijj = Module["dynCall_viiijj"] = Module["asm"]["$a"]).apply( + return (dynCall_viiijj = Module["dynCall_viiijj"] = Module["asm"]["ab"]).apply( null, arguments, ) }) var dynCall_ji = (Module["dynCall_ji"] = function () { - return (dynCall_ji = Module["dynCall_ji"] = Module["asm"]["ab"]).apply(null, arguments) + return (dynCall_ji = Module["dynCall_ji"] = Module["asm"]["bb"]).apply(null, arguments) }) var dynCall_viiij = (Module["dynCall_viiij"] = function () { - return (dynCall_viiij = Module["dynCall_viiij"] = Module["asm"]["bb"]).apply( + return (dynCall_viiij = Module["dynCall_viiij"] = Module["asm"]["cb"]).apply( null, arguments, ) }) var dynCall_viij = (Module["dynCall_viij"] = function () { - return (dynCall_viij = Module["dynCall_viij"] = Module["asm"]["cb"]).apply( + return (dynCall_viij = Module["dynCall_viij"] = Module["asm"]["db"]).apply( null, arguments, ) }) var dynCall_vij = (Module["dynCall_vij"] = function () { - return (dynCall_vij = Module["dynCall_vij"] = Module["asm"]["db"]).apply( + return (dynCall_vij = Module["dynCall_vij"] = Module["asm"]["eb"]).apply( null, arguments, ) }) var dynCall_jijj = (Module["dynCall_jijj"] = function () { - return (dynCall_jijj = Module["dynCall_jijj"] = Module["asm"]["eb"]).apply( + return (dynCall_jijj = Module["dynCall_jijj"] = Module["asm"]["fb"]).apply( null, arguments, ) }) var dynCall_iiji = (Module["dynCall_iiji"] = function () { - return (dynCall_iiji = Module["dynCall_iiji"] = Module["asm"]["fb"]).apply( + return (dynCall_iiji = Module["dynCall_iiji"] = Module["asm"]["gb"]).apply( null, arguments, ) }) var dynCall_jii = (Module["dynCall_jii"] = function () { - return (dynCall_jii = Module["dynCall_jii"] = Module["asm"]["gb"]).apply( + return (dynCall_jii = Module["dynCall_jii"] = Module["asm"]["hb"]).apply( null, arguments, ) }) var dynCall_viji = (Module["dynCall_viji"] = function () { - return (dynCall_viji = Module["dynCall_viji"] = Module["asm"]["hb"]).apply( + return (dynCall_viji = Module["dynCall_viji"] = Module["asm"]["ib"]).apply( null, arguments, ) }) var dynCall_iiiij = (Module["dynCall_iiiij"] = function () { - return (dynCall_iiiij = Module["dynCall_iiiij"] = Module["asm"]["ib"]).apply( + return (dynCall_iiiij = Module["dynCall_iiiij"] = Module["asm"]["jb"]).apply( null, arguments, ) }) var dynCall_viiijjj = (Module["dynCall_viiijjj"] = function () { - return (dynCall_viiijjj = Module["dynCall_viiijjj"] = Module["asm"]["jb"]).apply( + return (dynCall_viiijjj = Module["dynCall_viiijjj"] = Module["asm"]["kb"]).apply( null, arguments, ) }) var dynCall_iiiiij = (Module["dynCall_iiiiij"] = function () { - return (dynCall_iiiiij = Module["dynCall_iiiiij"] = Module["asm"]["kb"]).apply( + return (dynCall_iiiiij = Module["dynCall_iiiiij"] = Module["asm"]["lb"]).apply( null, arguments, ) }) var dynCall_jiiii = (Module["dynCall_jiiii"] = function () { - return (dynCall_jiiii = Module["dynCall_jiiii"] = Module["asm"]["lb"]).apply( + return (dynCall_jiiii = Module["dynCall_jiiii"] = Module["asm"]["mb"]).apply( null, arguments, ) @@ -5537,6 +5541,16 @@ var CompilerModule = (() => { _setThrew(1, 0) } } + function invoke_vii(index, a1, a2) { + var sp = stackSave() + try { + getWasmTableEntry(index)(a1, a2) + } catch (e) { + stackRestore(sp) + if (e !== e + 0) throw e + _setThrew(1, 0) + } + } function invoke_iiii(index, a1, a2, a3) { var sp = stackSave() try { @@ -5587,10 +5601,10 @@ var CompilerModule = (() => { _setThrew(1, 0) } } - function invoke_vii(index, a1, a2) { + function invoke_iiiiiiii(index, a1, a2, a3, a4, a5, a6, a7) { var sp = stackSave() try { - getWasmTableEntry(index)(a1, a2) + return getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6, a7) } catch (e) { stackRestore(sp) if (e !== e + 0) throw e @@ -5647,16 +5661,6 @@ var CompilerModule = (() => { _setThrew(1, 0) } } - function invoke_iiiiiiii(index, a1, a2, a3, a4, a5, a6, a7) { - var sp = stackSave() - try { - return getWasmTableEntry(index)(a1, a2, a3, a4, a5, a6, a7) - } catch (e) { - stackRestore(sp) - if (e !== e + 0) throw e - _setThrew(1, 0) - } - } function invoke_viiiiii(index, a1, a2, a3, a4, a5, a6) { var sp = stackSave() try { diff --git a/src/fift/funcfiftlib.wasm b/src/fift/funcfiftlib.wasm index b57796b..7da5b40 100755 Binary files a/src/fift/funcfiftlib.wasm and b/src/fift/funcfiftlib.wasm differ diff --git a/src/index.ts b/src/index.ts index 4be8e15..87a9beb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,8 @@ export { export type {AssemblyWriterOptions} from "./printer/assembly-writer" export {AssemblyWriter} from "./printer/assembly-writer" +export type {SourceMap, ProcedureHash} from "./decompiler/source-map" +export {obtainSourceMap} from "./decompiler/source-map" export {debugSymbols} from "./utils/known-methods" export {Cell} from "@ton/core" @@ -17,4 +19,4 @@ export type { FiftCompilationResultOk, FiftCompilationResultError, } from "./fift/compileFift" -export {compileFift} from "./fift/compileFift" +export {compileFift, compileFiftForSourceMap} from "./fift/compileFift" diff --git a/src/printer/assembly-writer.ts b/src/printer/assembly-writer.ts index b7a5569..acfa6b3 100644 --- a/src/printer/assembly-writer.ts +++ b/src/printer/assembly-writer.ts @@ -52,6 +52,18 @@ export interface AssemblyWriterOptions { */ readonly outputBitcodeAfterInstruction?: boolean readonly debugSymbols?: DebugSymbols + /** + * Map of function hashes to their original names. + * Used to restore original function names when printing. + * + * Can be obtained using `obtainSourceMap()` with original `.fif` file passed in: + * + * ```typescript + * const sourceMap = await obtainSourceMap("path/to/original.fif") + * const result = AssemblyWriter.write(program, { sourceMap }) + * ``` + */ + readonly sourceMap?: Map } export class AssemblyWriter { @@ -67,6 +79,16 @@ export class AssemblyWriter { public constructor(options: AssemblyWriterOptions) { const actualDebugSymbols = options.debugSymbols ?? debugSymbols + if (options.sourceMap) { + options.sourceMap.entries().forEach(([hash, name]) => { + actualDebugSymbols.procedures.push({ + name: name, + cellHash: hash, + methodId: -9999, + }) + }) + } + actualDebugSymbols.globals.forEach(glob => { this.knownGlobals.set(glob.index, glob.name) }) diff --git a/src/test/e2e/__snapshots__/decompile-with-debug-info.spec.ts.snap b/src/test/e2e/__snapshots__/decompile-with-debug-info.spec.ts.snap new file mode 100644 index 0000000..f891e2b --- /dev/null +++ b/src/test/e2e/__snapshots__/decompile-with-debug-info.spec.ts.snap @@ -0,0 +1,1040 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`disassemble > should decompile JettonMinter with debug info 1`] = ` +""Asm.fif" include +PROGRAM{ + DECLPROC recv_internal + 83229 DECLMETHOD owner + 103289 DECLMETHOD get_wallet_address + 106029 DECLMETHOD get_jetton_data + 115390 DECLMETHOD lazy_deployment_completed + DECLPROC $JettonMinter$_contract_router_internal + DECLPROC ?fun_ref_42dfbe7c44ef3021 + DECLPROC ?fun_ref_44086a5ce86162fe + DECLPROC ?fun_ref_5107b8836cd326d2 + DECLPROC ?fun_ref_71bde1515a4deb68 + DECLPROC $JettonMinter$_internal_binary_Mint + DECLPROC ?fun_ref_acfa8729a67010cf + DECLPROC ?fun_ref_b5b464853112a273 + DECLPROC $JettonMinter$_internal_binary_ProvideWalletAddress + DECLPROC ?fun_ref_e1b5bb080fc73cd8 + DECLPROC ?fun_ref_ec4e6a4d4bc86e9f + recv_internal PROC:<{ + s0 s1 XCHG // 0x0 + CTOS // 0xD0 + 4 LDU // 0xD3 03 + s0 s1 XCHG // 0x0 + 1 PUSHINT // 0x7 1 + AND // 0xB0 + NEGATE // 0xA3 + s0 s1 XCHG // 0x0 + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 s4 s2 PUXCPU // 0x545 0 5 3 + s0 s3 XCHG // 0x0 + 4 TUPLE // 0x6F0 4 + 1 SETGLOB // 0xF87_ 0C_ + s0 s2 XCHG // 0x0 + 2 SETGLOB // 0xF87_ 14_ + ?fun_ref_acfa8729a67010cf INLINECALLDICT // 0x + 2 4 BLKSWAP // 0x55 1 3 + $JettonMinter$_contract_router_internal INLINECALLDICT // 0x + 130 THROWIFNOT // 0xF2E4_ 105_ + NEWC // 0xC8 + 3 GETGLOB // 0xF85_ 1C_ + s0 s1 XCHG // 0x0 + STREF // 0xCC + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + 4 1 BLKSWAP // 0x55 3 0 + s4 s3 XCHG2 // 0x50 4 3 + STGRAMS // 0xFA02 + 1 STI // 0xCA 00 + ROT // 0x58 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + STSLICER // 0xCF16 + STREF // 0xCC + ENDC // 0xC9 + c4 POPCTR // 0xED5 4 + }> + owner PROC:<{ + ?fun_ref_acfa8729a67010cf INLINECALLDICT // 0x + ?fun_ref_44086a5ce86162fe INLINECALLDICT // 0x + 4 1 BLKDROP2 // 0x6C 4 1 + }> + get_wallet_address PROC:<{ + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + ?fun_ref_acfa8729a67010cf INLINECALLDICT // 0x + 1 4 BLKSWAP // 0x55 0 3 + ?fun_ref_71bde1515a4deb68 INLINECALLDICT // 0x + 4 1 BLKDROP2 // 0x6C 4 1 + }> + get_jetton_data PROC:<{ + ?fun_ref_acfa8729a67010cf INLINECALLDICT // 0x + ?fun_ref_b5b464853112a273 INLINECALLDICT // 0x + 4 5 BLKDROP2 // 0x6C 4 5 + }> + lazy_deployment_completed PROC:<{ + c4 PUSHCTR // 0xED4 4 + CTOS // 0xD0 + 1 LDI // 0xD2 00 + s0 s1 XCHG // 0x0 + }> + $JettonMinter$_contract_router_internal PROCREF:<{ + s0 s1 XCHG // 0x0 + <{ + 32 PUSHINT // 0x80 20 + SDSKIPFIRST // 0xD721 + 0 PUSHINT // 0x7 0 + s1 PUSH // 0x2 1 + SBITS // 0xD749 + 31 GTINT // 0xC2 1F + <{ + s0 POP // 0x3 0 + s0 PUSH // 0x2 0 + 32 PLDU // 0xD70B 1F + }> PUSHCONT // 0x9 3020D70B1F + IF // 0xDE + 395134233 PUSHINT // 0x82 10178D4519 + EQUAL // 0xBA + <{ + 32 LDU // 0xD3 1F + s0 s1 XCHG // 0x0 + 395134233 PUSHINT // 0x82 10178D4519 + EQUAL // 0xBA + 129 THROWIFNOT // 0xF2E4_ 103_ + 64 LDU // 0xD3 3F + LDGRAMS // 0xFA00 + ROTREV // 0x59 + 1 2 BLKDROP2 // 0x6C 1 2 + s1 POP // 0x3 1 + s1 s4 XCHG // 0x1 + SUB // 0xA1 + s0 s3 XCHG // 0x0 + -1 PUSHINT // 0x7 F + }> PUSHCONT // 0x8F_ D31F018210178D4519BAF2E081D33FFA00596C123114A1037F + IFJMP // 0xE0 + s0 POP // 0x3 0 + -1 PUSHINT // 0x7 F + }> PUSHCONT // 0x8F_ 8020D7217021D749C21F953020D70B1FDE8210178D4519BA8E19D31F018210178D4519BAF2E081D33FFA00596C123114A1037FE0307F + IFJMP // 0xE0 + 0 PUSHINT // 0x7 0 + s1 PUSH // 0x2 1 + SBITS // 0xD749 + 31 GTINT // 0xC2 1F + <{ + s0 POP // 0x3 0 + s0 PUSH // 0x2 0 + 32 PLDU // 0xD70B 1F + }> PUSHCONT // 0x9 3020D70B1F + IF // 0xDE + s0 PUSH // 0x2 0 + 2078119902 PUSHINT // 0x82 107BDD97DE + EQUAL // 0xBA + <{ + s0 POP // 0x3 0 + 32 LDU // 0xD3 1F + s0 s1 XCHG // 0x0 + 2078119902 PUSHINT // 0x82 107BDD97DE + EQUAL // 0xBA + 129 THROWIFNOT // 0xF2E4_ 103_ + 64 LDU // 0xD3 3F + LDGRAMS // 0xFA00 + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 s1 XCHG // 0x0 + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s1 s4 XCHG // 0x1 + s3 s3 s0 XCHG3 // 0x4 3 3 0 + 1 4 BLKDROP2 // 0x6C 1 4 + s4 s7 XCHG // 0x10 + s3 s6 XCHG // 0x10 + s5 s7 s7 XCHG3 // 0x4 5 7 7 + 3 GETGLOB // 0xF85_ 1C_ + 8 GETPARAM // 0xF82 8 + s1 s2 XCHG // 0x1 + ?fun_ref_e1b5bb080fc73cd8 INLINECALLDICT // 0x + 0 PUSHINT // 0x7 0 + ROTREV // 0x59 + NEWC // 0xC8 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 3 PUSHINT // 0x7 3 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + STREF // 0xCC + STREF // 0xCC + ENDC // 0xC9 + HASHCU // 0xF900 + NEWC // 0xC8 + 2 PUSHINT // 0x7 2 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + 8 STI // 0xCA 07 + 256 STU // 0xCB FF + ENDC // 0xC9 + CTOS // 0xD0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + 2 GETGLOB // 0xF85_ 14_ + SDEQ // 0xC705 + 74 THROWIFNOT // 0xF2E4_ 095_ + s3 s4 XCHG2 // 0x50 3 4 + SUB // 0xA1 + 0 PUSHINT // 0x7 0 + 0 PUSHINT // 0x7 0 + 66 PUSHINT // 0x80 42 + s0 s7 XCHG // 0x0 + NEWC // 0xC8 + s0 s1 XCHG // 0x0 + 3576854235 PUSHINT // 0x82 10D53276DB + ROT // 0x58 + 32 STU // 0xCB 1F + 64 STU // 0xCB 3F + ENDC // 0xC9 + s4 s8 XCHG // 0x10 + s1 s3 s0 XCHG3 // 0x4 1 3 0 + s1 s7 XCHG // 0x1 + s2 s4 XCHG // 0x10 + s2 s3 XCHG // 0x10 + NULL // 0x6D + NULL // 0x6D + ?fun_ref_5107b8836cd326d2 INLINECALLDICT // 0x + s0 POP // 0x3 0 + s3 s0 s0 XCHG3 // 0x4 3 0 0 + -1 PUSHINT // 0x7 F + }>c IFJMPREF // 0xE302 30D31F0182107BDD97DEBAF2E081D33FFA00FA400120D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E08801FA400120D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E0881443306C14 + s0 PUSH // 0x2 0 + 3 EQINT // 0xC0 03 + <{ + s0 POP // 0x3 0 + 32 LDU // 0xD3 1F + s0 s1 XCHG // 0x0 + 3 EQINT // 0xC0 03 + 129 THROWIFNOT // 0xF2E4_ 103_ + 64 LDU // 0xD3 3F + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s1 s2 XCHG // 0x1 + 1 2 BLKDROP2 // 0x6C 1 2 + s1 POP // 0x3 1 + 2 GETGLOB // 0xF85_ 14_ + s1 s3 XCHG // 0x1 + SDEQ // 0xC705 + 73 THROWIFNOT // 0xF2E4_ 093_ + -1 PUSHINT // 0x7 F + }>c IFJMPREF // 0xE302 30D31F01C003F2E081D33FFA400120D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E088126C1231F84213C705F2E0497F + s0 PUSH // 0x2 0 + 4 EQINT // 0xC0 04 + <{ + s0 POP // 0x3 0 + 32 LDU // 0xD3 1F + s0 s1 XCHG // 0x0 + 4 EQINT // 0xC0 04 + 129 THROWIFNOT // 0xF2E4_ 103_ + LDREF // 0xD4 + s0 s1 XCHG // 0x0 + s1 POP // 0x3 1 + s1 POP // 0x3 1 + 2 GETGLOB // 0xF85_ 14_ + s2 s(-1) PUXC // 0x52 2 0 + SDEQ // 0xC705 + 73 THROWIFNOT // 0xF2E4_ 093_ + -1 PUSHINT // 0x7 F + }> PUSHCONT // 0x8F_ 30D31F01C004F2E081D4013131F8425220C705F2E0497F + IFJMP // 0xE0 + s0 PUSH // 0x2 0 + 745978227 PUSHINT // 0x82 102C76B973 + EQUAL // 0xBA + <{ + s0 POP // 0x3 0 + 32 LDU // 0xD3 1F + s0 s1 XCHG // 0x0 + 745978227 PUSHINT // 0x82 102C76B973 + EQUAL // 0xBA + 129 THROWIFNOT // 0xF2E4_ 103_ + 64 LDU // 0xD3 3F + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 s1 XCHG // 0x0 + 1 LDI // 0xD2 00 + 3 1 BLKSWAP // 0x55 2 0 + 1 3 BLKDROP2 // 0x6C 1 3 + $JettonMinter$_internal_binary_ProvideWalletAddress INLINECALLDICT // 0x + -1 PUSHINT // 0x7 F + }> PUSHCONT // 0x8F_ 30D31F0182102C76B973BAF2E081D33FFA400120D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E08801D20055206C13DB3C7F + IFJMP // 0xE0 + 21 EQINT // 0xC0 15 + <{ + 32 LDU // 0xD3 1F + s0 s1 XCHG // 0x0 + 21 EQINT // 0xC0 15 + 129 THROWIFNOT // 0xF2E4_ 103_ + 64 LDU // 0xD3 3F + 257 PUSHINT // 0x81 0101 + LDIX // 0xD700 + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s3 s3 s0 XCHG3 // 0x4 3 3 0 + 1 3 BLKDROP2 // 0x6C 1 3 + $JettonMinter$_internal_binary_Mint INLINECALLDICT // 0x + -1 PUSHINT // 0x7 F + }> PUSHCONT // 0x8F_ D31F01C015F2E081D33F810101D700FA400120D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E08843306C13DB3C7F + IFJMP // 0xE0 + s0 POP // 0x3 0 + 0 PUSHINT // 0x7 0 + }> + ?fun_ref_42dfbe7c44ef3021 PROCREF:<{ + 0 PUSHINT // 0x7 0 + s0 s2 XCHG // 0x0 + -1 PUSHINT // 0x7 F + s0 s2 XCHG // 0x0 + }> + ?fun_ref_44086a5ce86162fe PROCREF:<{ + s1 PUSH // 0x2 1 + }> + ?fun_ref_5107b8836cd326d2 PROCREF:<{ + NEWC // 0xC8 + 1 PUSHINT // 0x7 1 + s0 s1 XCHG // 0x0 + 2 STI // 0xCA 01 + s0 s7 XCHG2 // 0x50 0 7 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 3 STI // 0xCA 02 + s0 s5 XCHG2 // 0x50 0 5 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + STSLICER // 0xCF16 + s0 s3 XCHG2 // 0x50 0 3 + STGRAMS // 0xFA02 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 105 STI // 0xCA 68 + s3 PUSH // 0x2 3 + ISNULL // 0x6E + NOT // 0xB3 + <{ + -1 PUSHINT // 0x7 F + }> PUSHCONT // 0x9 7F + <{ + s4 PUSH // 0x2 4 + ISNULL // 0x6E + NOT // 0xB3 + }> PUSHCONT // 0x9 246EB3 + IFELSE // 0xE2 + <{ + s3 POP // 0x3 3 + s3 POP // 0x3 3 + s0 s1 XCHG // 0x0 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + }> PUSHCONT // 0x9 3333017001CA00 + <{ + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + NEWC // 0xC8 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s4 PUSH // 0x2 4 + ISNULL // 0x6E + NOT // 0xB3 + <{ + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s0 s4 XCHG // 0x0 + s0 PUSH // 0x2 0 + ISNULL // 0x6E + 128 THROWIF // 0xF2D4_ 101_ + s0 s4 XCHG2 // 0x50 0 4 + STREF // 0xCC + }> PUSHCONT // 0x9 7F01CA0004206EF2D0805004CC + <{ + s4 POP // 0x3 4 + s0 s3 XCHG // 0x0 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + }> PUSHCONT // 0x9 34037001CA00 + IFELSE // 0xE2 + s4 PUSH // 0x2 4 + ISNULL // 0x6E + NOT // 0xB3 + <{ + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s0 s4 XCHG // 0x0 + s0 PUSH // 0x2 0 + ISNULL // 0x6E + 128 THROWIF // 0xF2D4_ 101_ + s0 s4 XCHG2 // 0x50 0 4 + STREF // 0xCC + }> PUSHCONT // 0x9 7F01CA0004206EF2D0805004CC + <{ + s4 POP // 0x3 4 + s0 s3 XCHG // 0x0 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + }> PUSHCONT // 0x9 34037001CA00 + IFELSE // 0xE2 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s0 s2 XCHG // 0x0 + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s0 s2 XCHG // 0x0 + ENDC // 0xC9 + ROT // 0x58 + STREF // 0xCC + }>c IFREFELSE // 0xE30D 7F01CA00C87001CA007001CA00246EB39D7F01CA0004206EF2D0805004CC9634037001CA00E2246EB39D7F01CA0004206EF2D0805004CC9634037001CA00E27001CA00027F01CA0002C958CC + s1 PUSH // 0x2 1 + ISNULL // 0x6E + NOT // 0xB3 + <{ + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + ISNULL // 0x6E + 128 THROWIF // 0xF2D4_ 101_ + s0 s1 XCHG // 0x0 + STREF // 0xCC + }> PUSHCONT // 0x9 7F01CA0001206EF2D08001CC + <{ + s1 POP // 0x3 1 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + }> PUSHCONT // 0x9 317001CA00 + IFELSE // 0xE2 + ENDC // 0xC9 + s0 s1 XCHG // 0x0 + SENDMSG // 0xFB08 + }> + ?fun_ref_71bde1515a4deb68 PROCREF:<{ + 3 GETGLOB // 0xF85_ 1C_ + 8 GETPARAM // 0xF82 8 + s1 s2 XCHG // 0x1 + ?fun_ref_e1b5bb080fc73cd8 INLINECALLDICT // 0x + 0 PUSHINT // 0x7 0 + ROTREV // 0x59 + NEWC // 0xC8 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 3 PUSHINT // 0x7 3 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + STREF // 0xCC + STREF // 0xCC + ENDC // 0xC9 + HASHCU // 0xF900 + NEWC // 0xC8 + 2 PUSHINT // 0x7 2 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + 8 STI // 0xCA 07 + 256 STU // 0xCB FF + ENDC // 0xC9 + CTOS // 0xD0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + }> + $JettonMinter$_internal_binary_Mint PROCREF:<{ + 2 GETGLOB // 0xF85_ 14_ + s5 s(-1) PUXC // 0x52 5 0 + SDEQ // 0xC705 + 73 THROWIFNOT // 0xF2E4_ 093_ + 3688 PUSHINT // 0x81 0E68 + s6 PUSH // 0x2 6 + THROWANYIFNOT // 0xF2F4 + s6 s1 XCPU // 0x51 6 1 + ADD // 0xA0 + s0 s4 XCHG // 0x0 + s3 s5 XCHG // 0x10 + s0 s5 s6 XCHG3 // 0x4 0 5 6 + 3 GETGLOB // 0xF85_ 1C_ + 8 GETPARAM // 0xF82 8 + s1 s2 XCHG // 0x1 + ?fun_ref_e1b5bb080fc73cd8 INLINECALLDICT // 0x + DUP2 // 0x5C + 0 PUSHINT // 0x7 0 + ROTREV // 0x59 + NEWC // 0xC8 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 3 PUSHINT // 0x7 3 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + STREF // 0xCC + STREF // 0xCC + ENDC // 0xC9 + HASHCU // 0xF900 + NEWC // 0xC8 + 2 PUSHINT // 0x7 2 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + 8 STI // 0xCA 07 + 256 STU // 0xCB FF + ENDC // 0xC9 + CTOS // 0xD0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + 0 PUSHINT // 0x7 0 + -1 PUSHINT // 0x7 F + 64 PUSHINT // 0x80 40 + 8 GETPARAM // 0xF82 8 + 1 PUSHINT // 0x7 1 + NEWC // 0xC8 + ENDC // 0xC9 + CTOS // 0xD0 + s10 PUSH // 0x2 A + s5 s15 XCHG // 0x10 + s4 s14 XCHG // 0x10 + ROTREV // 0x59 + NEWC // 0xC8 + 6 1 BLKSWAP // 0x55 5 0 + ?fun_ref_ec4e6a4d4bc86e9f INLINECALLDICT // 0x + ENDC // 0xC9 + s6 s5 s0 XCHG3 // 0x4 6 5 0 + s4 s10 XCHG // 0x10 + s3 s9 XCHG // 0x10 + s0 s10 s9 XCHG3 // 0x4 0 A 9 + s4 s6 XCHG // 0x10 + s4 s5 XCHG // 0x10 + ?fun_ref_5107b8836cd326d2 INLINECALLDICT // 0x + s0 POP // 0x3 0 + s0 s0 s3 XCHG3 // 0x4 0 0 3 + }> + ?fun_ref_acfa8729a67010cf PROCREF:<{ + c4 PUSHCTR // 0xED4 4 + CTOS // 0xD0 + LDREF // 0xD4 + s0 s1 XCHG // 0x0 + 3 SETGLOB // 0xF87_ 1C_ + 1 LDI // 0xD2 00 + s0 s1 XCHG // 0x0 + <{ + LDGRAMS // 0xFA00 + 1 LDI // 0xD2 00 + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 s1 XCHG // 0x0 + LDREF // 0xD4 + 4 1 BLKSWAP // 0x55 3 0 + 1 4 BLKDROP2 // 0x6C 1 4 + }> PUSHCONT // 0x8F_ FA00D200FA400120D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E08801D455306C14 + IFJMP // 0xE0 + LDMSGADDR // 0xFA40 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 s1 XCHG // 0x0 + LDREF // 0xD4 + ROTREV // 0x59 + s0 s2 XCHG // 0x0 + ENDS // 0xD1 + s0 s1 XCHG // 0x0 + ?fun_ref_42dfbe7c44ef3021 INLINECALLDICT // 0x + }> + ?fun_ref_b5b464853112a273 PROCREF:<{ + 3 GETGLOB // 0xF85_ 1C_ + 8 GETPARAM // 0xF82 8 + 8 GETPARAM // 0xF82 8 + ?fun_ref_e1b5bb080fc73cd8 INLINECALLDICT // 0x + s0 POP // 0x3 0 + s4 s3 s(-2) PU2XC // 0x546 4 4 0 + s4 s3 s(-2) PU2XC // 0x546 4 4 0 + }> + $JettonMinter$_internal_binary_ProvideWalletAddress PROCREF:<{ + 1 GETGLOB // 0xF85_ 0C_ + 4 UNTUPLE // 0x6F2 4 + s1 s3 XCHG // 0x1 + 3 BLKDROP // 0x5F0 3 + 6705600 PUSHINT // 0x82 086651C0 + GEQ // 0xBE + 75 THROWIFNOT // 0xF2E4_ 097_ + NULL // 0x6D + s2 PUSH // 0x2 2 + REWRITESTDADDR // 0xFA44 + s0 POP // 0x3 0 + x{2_} PUSHSLICE // 0x8B 2_ + s0 s1 XCHG // 0x0 + 0 EQINT // 0xC0 00 + <{ + s0 POP // 0x3 0 + 3 GETGLOB // 0xF85_ 1C_ + 8 GETPARAM // 0xF82 8 + s4 s(-1) PUXC // 0x52 4 0 + ?fun_ref_e1b5bb080fc73cd8 INLINECALLDICT // 0x + 0 PUSHINT // 0x7 0 + ROTREV // 0x59 + NEWC // 0xC8 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 3 PUSHINT // 0x7 3 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + STREF // 0xCC + STREF // 0xCC + ENDC // 0xC9 + HASHCU // 0xF900 + NEWC // 0xC8 + 2 PUSHINT // 0x7 2 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STU // 0xCB 00 + s1 s2 XCHG // 0x1 + 8 STI // 0xCA 07 + 256 STU // 0xCB FF + ENDC // 0xC9 + CTOS // 0xD0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + }> PUSHCONT // 0x8F_ 30F843F8285240DB3C7059C87001CB017301CB017001CB0012CCCCC9F900C87201CB017001CB0012CA07CBFFC9D020D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E088 + IF // 0xDE + s0 s2 XCHG // 0x0 + <{ + s0 POP // 0x3 0 + }> PUSHCONT // 0x9 30 + <{ + s2 POP // 0x3 2 + }> PUSHCONT // 0x9 32 + IFELSE // 0xE2 + 2 GETGLOB // 0xF85_ 14_ + s4 s7 XCHG // 0x10 + s3 s6 XCHG // 0x10 + s5 s1 s7 XCHG3 // 0x4 5 1 7 + 0 PUSHINT // 0x7 0 + s2 s6 XCHG2 // 0x50 2 6 + 64 PUSHINT // 0x80 40 + s0 s8 XCHG // 0x0 + NEWC // 0xC8 + 3513996288 PUSHINT // 0x82 10D1735400 + s0 s1 XCHG // 0x0 + 32 STU // 0xCB 1F + 64 STU // 0xCB 3F + ROT // 0x58 + STSLICER // 0xCF16 + s1 PUSH // 0x2 1 + ISNULL // 0x6E + NOT // 0xB3 + <{ + NEWC // 0xC8 + s0 s2 XCHG // 0x0 + s0 PUSH // 0x2 0 + ISNULL // 0x6E + 128 THROWIF // 0xF2D4_ 101_ + s1 s2 XCHG // 0x1 + STSLICER // 0xCF16 + ENDC // 0xC9 + s0 s1 XCHG // 0x0 + -1 PUSHINT // 0x7 F + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + STREF // 0xCC + }> PUSHCONT // 0x8F_ C802206EF2D08012CF16C9017F01CA00CC + <{ + s1 POP // 0x3 1 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + }> PUSHCONT // 0x9 317001CA00 + IFELSE // 0xE2 + ENDC // 0xC9 + s3 s7 XCHG // 0x10 + s5 s6 s0 XCHG3 // 0x4 5 6 0 + -1 PUSHINT // 0x7 F + 4 1 BLKSWAP // 0x55 3 0 + NULL // 0x6D + NULL // 0x6D + ?fun_ref_5107b8836cd326d2 INLINECALLDICT // 0x + s0 POP // 0x3 0 + s3 s1 s3 XCHG3 // 0x4 3 1 3 + }> + ?fun_ref_e1b5bb080fc73cd8 PROCREF:<{ + s0 s2 XCHG // 0x0 + CTOS // 0xD0 + LDDICT // 0xF404 + s0 POP // 0x3 0 + NULL // 0x6D + s0 s1 XCHG // 0x0 + 3765 PUSHINT // 0x81 0EB5 + s0 s1 XCHG // 0x0 + 16 PUSHINT // 0x80 10 + DICTUGETREF // 0xF40F + NULLSWAPIFNOT // 0x6FA1 + 135 THROWIFNOT // 0xF2E4_ 10F_ + s0 s1 XCHG // 0x0 + 3765 PUSHINT // 0x81 0EB5 + s2 PUSH // 0x2 2 + s0 s2 XCHG // 0x0 + 16 PUSHINT // 0x80 10 + DICTUSETREF // 0xF417 + NEWC // 0xC8 + s0 s1 XCHG // 0x0 + NEWC // 0xC8 + STDICT // 0xF400 + ENDC // 0xC9 + s0 s1 XCHG // 0x0 + STREF // 0xCC + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 1 STI // 0xCA 00 + s0 s0 s3 XCHG3 // 0x4 0 0 3 + ROTREV // 0x59 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + STSLICER // 0xCF16 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + STSLICER // 0xCF16 + ENDC // 0xC9 + }> + ?fun_ref_ec4e6a4d4bc86e9f PROCREF:<{ + 395134233 PUSHINT // 0x82 10178D4519 + s0 s7 XCHG2 // 0x50 0 7 + 32 STU // 0xCB 1F + s1 s5 XCHG // 0x1 + 64 STU // 0xCB 3F + s0 s3 XCHG2 // 0x50 0 3 + STGRAMS // 0xFA02 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + STSLICER // 0xCF16 + s0 s1 XCHG // 0x0 + s0 PUSH // 0x2 0 + ISNULL // 0x6E + <{ + s0 POP // 0x3 0 + 0 PUSHINT // 0x7 0 + s0 s1 XCHG // 0x0 + 2 STU // 0xCB 01 + }> PUSHCONT // 0x9 307001CB01 + <{ + s0 PUSH // 0x2 0 + SBITS // 0xD749 + 267 PUSHINT // 0x81 010B + EQUAL // 0xBA + 136 THROWIFNOT // 0xF2E4_ 111_ + s0 PUSH // 0x2 0 + 11 PLDU // 0xD70B 0A + s0 PUSH // 0x2 0 + 10 PUSHPOW2 // 0x83 09 + EQUAL // 0xBA + s0 s1 XCHG // 0x0 + 1279 PUSHINT // 0x81 04FF + EQUAL // 0xBA + OR // 0xB1 + 136 THROWIFNOT // 0xF2E4_ 111_ + STSLICER // 0xCF16 + }> PUSHCONT // 0x8F_ 20D74981010BBAF2E08820D70B0A208309BA018104FFBAB1F2E088CF16 + IFELSE // 0xE2 + s0 s1 XCHG // 0x0 + STGRAMS // 0xFA02 + s0 s1 XCHG // 0x0 + STSLICER // 0xCF16 + }> +}END>c" +`; diff --git a/src/test/e2e/__testdata__/Jetton_JettonMinter.code.fif b/src/test/e2e/__testdata__/Jetton_JettonMinter.code.fif new file mode 100644 index 0000000..33a7d5e --- /dev/null +++ b/src/test/e2e/__testdata__/Jetton_JettonMinter.code.fif @@ -0,0 +1,824 @@ +PROGRAM{ + DECLPROC __tact_verify_address + DECLPROC __tact_load_address + DECLPROC __tact_store_address + DECLPROC __tact_store_address_opt + DECLPROC __tact_create_address + DECLPROC __tact_compute_contract_address + DECLPROC __tact_not_null + DECLPROC __tact_context_get + DECLPROC __tact_context_get_sender + DECLPROC __tact_store_bool + DECLPROC __tact_slice_eq_bits + DECLPROC __tact_dict_set_code + DECLPROC __tact_dict_get_code + DECLPROC $CustomChangeOwner$_load + DECLPROC $TokenUpdateContent$_load + DECLPROC $TokenTransferInternal$_store + DECLPROC $TokenTransferInternal$_store_cell + DECLPROC $TokenTransferInternal$_load_bounced + DECLPROC $TokenBurnNotification$_load + DECLPROC $TokenExcesses$_store + DECLPROC $TokenExcesses$_store_cell + DECLPROC $ProvideWalletAddress$_load + DECLPROC $Mint$_load + DECLPROC $JettonMinter$_store + DECLPROC $JettonMinter$_load + DECLPROC $StateInit$_get_code + DECLPROC $StdAddress$_get_workchain + DECLPROC $Context$_get_value + DECLPROC $JettonMasterState$_to_external + DECLPROC $JettonWallet$init$_store + DECLPROC $JettonMinter$init$_load + DECLPROC $JettonMinter$_contract_init + DECLPROC $JettonMinter$_contract_load + DECLPROC $JettonMinter$_contract_store + DECLPROC $global_emptyCell + DECLPROC $Cell$_fun_asSlice + DECLPROC $global_emptySlice + DECLPROC $global_contractAddress + DECLPROC $global_send + DECLPROC $JettonWallet$_init_child + DECLPROC $JettonMinter$_fun_takeWalletBody + DECLPROC $JettonMinter$_fun_getJettonWalletInit + DECLPROC $JettonMinter$_fun_getJettonWalletByOwner + DECLPROC $JettonMasterState$_constructor_totalSupply_mintable_adminAddress_jettonContent_jettonWalletCode + DECLPROC $JettonMinter$_fun_get_jetton_data + DECLPROC $JettonMinter$_fun_get_wallet_address + DECLPROC $JettonMinter$_fun_owner + DECLPROC $SendParameters$_constructor_to_value_bounce_mode_body + DECLPROC $TokenExcesses$_constructor_query_id + DECLPROC $SendParameters$_constructor_to_value_mode_body + DECLPROC $SendParameters$_constructor_to_value_bounce_mode_body_code_data + DECLPROC $TokenTransferInternal$_constructor_query_id_amount_from_response_destination_forward_ton_amount_forward_payload + DECLPROC $JettonMinter$_internal_binary_TokenBurnNotification + DECLPROC $JettonMinter$_internal_binary_CustomChangeOwner + DECLPROC $JettonMinter$_internal_binary_TokenUpdateContent + DECLPROC $JettonMinter$_internal_binary_ProvideWalletAddress + DECLPROC $JettonMinter$_internal_binary_Mint + DECLPROC $JettonMinter$_receive_binary_bounce_TokenTransferInternal + 106029 DECLMETHOD %get_jetton_data + 103289 DECLMETHOD %get_wallet_address + 83229 DECLMETHOD %owner + 115390 DECLMETHOD lazy_deployment_completed + DECLPROC $JettonMinter$_contract_router_internal + DECLPROC recv_internal + DECLGLOBVAR __tact_context + DECLGLOBVAR __tact_context_sender + DECLGLOBVAR __tact_context_sys + DECLGLOBVAR __tact_randomized + __tact_verify_address PROCINLINE:<{ + DUP + SBITS + 267 PUSHINT + EQUAL + 136 THROWIFNOT + DUP + 11 PLDU + DUP + 10 PUSHPOW2 + EQUAL + SWAP + 1279 PUSHINT + EQUAL + OR + 136 THROWIFNOT + }> + __tact_load_address PROCINLINE:<{ + LDMSGADDR + SWAP + __tact_verify_address INLINECALLDICT + }> + __tact_store_address PROCINLINE:<{ + __tact_verify_address INLINECALLDICT + STSLICER + }> + __tact_store_address_opt PROCINLINE:<{ + DUP + ISNULL + IF:<{ + DROP + 0 PUSHINT + SWAP + 2 STU + }>ELSE<{ + __tact_store_address INLINECALLDICT + }> + }> + __tact_create_address PROCINLINE:<{ + NEWC + 2 PUSHINT + SWAP + 2 STU + 0 PUSHINT + SWAP + 1 STU + s1 s2 XCHG + 8 STI + 256 STU + ENDC + CTOS + __tact_verify_address INLINECALLDICT + }> + __tact_compute_contract_address PROCINLINE:<{ + NEWC + 0 PUSHINT + SWAP + 2 STU + 3 PUSHINT + SWAP + 2 STU + 0 PUSHINT + SWAP + 1 STU + s1 s2 XCHG + STREF + STREF + ENDC + HASHCU + __tact_create_address INLINECALLDICT + }> + __tact_not_null PROCINLINE:<{ + DUP + ISNULL + 128 THROWIF + }> + __tact_context_get PROCINLINE:<{ + __tact_context GETGLOB + 4 UNTUPLE + }> + __tact_context_get_sender PROCINLINE:<{ + __tact_context_sender GETGLOB + }> + __tact_store_bool PROCINLINE:<{ + SWAP + 1 STI + }> + __tact_slice_eq_bits PROCINLINE:<{ + SDEQ + }> + __tact_dict_set_code PROCINLINE:<{ + s0 s2 XCHG + 16 PUSHINT + DICTUSETREF + }> + __tact_dict_get_code PROCINLINE:<{ + SWAP + 16 PUSHINT + DICTUGETREF + NULLSWAPIFNOT + 135 THROWIFNOT + }> + $CustomChangeOwner$_load PROCINLINE:<{ + 32 LDU + SWAP + 3 EQINT + 129 THROWIFNOT + 64 LDU + __tact_load_address INLINECALLDICT + s1 s2 XCHG + }> + $TokenUpdateContent$_load PROCINLINE:<{ + 32 LDU + SWAP + 4 EQINT + 129 THROWIFNOT + LDREF + SWAP + }> + $TokenTransferInternal$_store PROCREF:<{ + 395134233 PUSHINT + s0 s7 XCHG2 + 32 STU + s1 s5 XCHG + 64 STU + s0 s3 XCHG2 + STVARUINT16 + SWAP + __tact_store_address INLINECALLDICT + SWAP + __tact_store_address_opt INLINECALLDICT + SWAP + STVARUINT16 + SWAP + STSLICER + }> + $TokenTransferInternal$_store_cell PROCINLINE:<{ + NEWC + 6 -ROLL + $TokenTransferInternal$_store INLINECALLDICT + ENDC + }> + $TokenTransferInternal$_load_bounced PROCINLINE:<{ + 32 LDU + SWAP + 395134233 PUSHINT + EQUAL + 129 THROWIFNOT + 64 LDU + LDVARUINT16 + -ROT + }> + $TokenBurnNotification$_load PROCINLINE:<{ + 32 LDU + SWAP + 2078119902 PUSHINT + EQUAL + 129 THROWIFNOT + 64 LDU + LDVARUINT16 + __tact_load_address INLINECALLDICT + SWAP + __tact_load_address INLINECALLDICT + s1 s4 XCHG + s3 s3 s0 XCHG3 + }> + $TokenExcesses$_store PROCINLINE:<{ + 3576854235 PUSHINT + ROT + 32 STU + 64 STU + }> + $TokenExcesses$_store_cell PROCINLINE:<{ + NEWC + SWAP + $TokenExcesses$_store INLINECALLDICT + ENDC + }> + $ProvideWalletAddress$_load PROCINLINE:<{ + 32 LDU + SWAP + 745978227 PUSHINT + EQUAL + 129 THROWIFNOT + 64 LDU + __tact_load_address INLINECALLDICT + SWAP + 1 LDI + 3 -ROLL + }> + $Mint$_load PROCINLINE:<{ + 32 LDU + SWAP + 21 EQINT + 129 THROWIFNOT + 64 LDU + 257 PUSHINT + LDIX + __tact_load_address INLINECALLDICT + s3 s3 s0 XCHG3 + }> + $JettonMinter$_store PROCINLINE:<{ + s4 s3 XCHG2 + STVARUINT16 + 1 STI + ROT + __tact_store_address INLINECALLDICT + STREF + }> + $JettonMinter$_load PROCINLINE:<{ + LDVARUINT16 + 1 LDI + __tact_load_address INLINECALLDICT + SWAP + LDREF + 4 -ROLL + }> + $StateInit$_get_code PROCINLINE:<{ + DROP + }> + $StdAddress$_get_workchain PROCINLINE:<{ + DROP + }> + $Context$_get_value PROCINLINE:<{ + s1 s3 XCHG + 3 BLKDROP + }> + $JettonMasterState$_to_external PROCINLINE:<{ + }> + $JettonWallet$init$_store PROCINLINE:<{ + -ROT + __tact_store_address INLINECALLDICT + SWAP + __tact_store_address INLINECALLDICT + }> + $JettonMinter$init$_load PROCINLINE:<{ + __tact_load_address INLINECALLDICT + SWAP + LDREF + -ROT + }> + $JettonMinter$_contract_init PROCREF:<{ + 0 PUSHINT + s0 s2 XCHG + TRUE + s0 s2 XCHG + }> + $JettonMinter$_contract_load PROCREF:<{ + c4 PUSH + CTOS + LDREF + SWAP + __tact_context_sys SETGLOB + 1 LDI + SWAP + IFJMP:<{ + $JettonMinter$_load INLINECALLDICT + 1 4 BLKDROP2 + }> + $JettonMinter$init$_load INLINECALLDICT + s0 s2 XCHG + ENDS + SWAP + $JettonMinter$_contract_init INLINECALLDICT + }> + $JettonMinter$_contract_store PROCINLINE:<{ + NEWC + __tact_context_sys GETGLOB + SWAP + STREF + TRUE + SWAP + 1 STI + 4 -ROLL + $JettonMinter$_store INLINECALLDICT + ENDC + c4 POP + }> + $global_emptyCell PROCINLINE:<{ + NEWC + ENDC + }> + $Cell$_fun_asSlice PROCINLINE:<{ + CTOS + }> + $global_emptySlice PROCINLINE:<{ + $global_emptyCell INLINECALLDICT + $Cell$_fun_asSlice INLINECALLDICT + }> + $global_contractAddress PROCINLINE:<{ + 0 PUSHINT + -ROT + __tact_compute_contract_address INLINECALLDICT + }> + $global_send PROCREF:<{ + NEWC + 1 PUSHINT + SWAP + 2 STI + s0 s7 XCHG2 + __tact_store_bool INLINECALLDICT + 0 PUSHINT + SWAP + 3 STI + s0 s5 XCHG2 + __tact_store_address INLINECALLDICT + s0 s3 XCHG2 + STVARUINT16 + 0 PUSHINT + SWAP + 105 STI + s3 PUSH + ISNULL + NOT + IF:<{ + TRUE + }>ELSE<{ + s4 PUSH + ISNULL + NOT + }> + IF:<{ + TRUE + __tact_store_bool INLINECALLDICT + NEWC + FALSE + __tact_store_bool INLINECALLDICT + FALSE + __tact_store_bool INLINECALLDICT + s4 PUSH + ISNULL + NOT + IF:<{ + TRUE + __tact_store_bool INLINECALLDICT + s0 s4 XCHG + __tact_not_null INLINECALLDICT + s0 s4 XCHG2 + STREF + }>ELSE<{ + s4 POP + s0 s3 XCHG + FALSE + __tact_store_bool INLINECALLDICT + }> + s4 PUSH + ISNULL + NOT + IF:<{ + TRUE + __tact_store_bool INLINECALLDICT + s0 s4 XCHG + __tact_not_null INLINECALLDICT + s0 s4 XCHG2 + STREF + }>ELSE<{ + s4 POP + s0 s3 XCHG + FALSE + __tact_store_bool INLINECALLDICT + }> + FALSE + __tact_store_bool INLINECALLDICT + s0 s2 XCHG + TRUE + __tact_store_bool INLINECALLDICT + s0 s2 XCHG + ENDC + ROT + STREF + }>ELSE<{ + s3 POP + s3 POP + SWAP + FALSE + __tact_store_bool INLINECALLDICT + }> + OVER + ISNULL + NOT + IF:<{ + TRUE + __tact_store_bool INLINECALLDICT + SWAP + __tact_not_null INLINECALLDICT + SWAP + STREF + }>ELSE<{ + NIP + FALSE + __tact_store_bool INLINECALLDICT + }> + ENDC + SWAP + SENDMSG + }> + $JettonWallet$_init_child PROCREF:<{ + s0 s2 XCHG + CTOS + LDDICT + DROP + NEWDICT + SWAP + 3765 PUSHINT + __tact_dict_get_code INLINECALLDICT + SWAP + 3765 PUSHINT + s2 PUSH + __tact_dict_set_code INLINECALLDICT + NEWC + SWAP + NEWC + STDICT + ENDC + SWAP + STREF + FALSE + SWAP + 1 STI + s0 s0 s3 XCHG3 + $JettonWallet$init$_store INLINECALLDICT + ENDC + }> + $JettonMinter$_fun_takeWalletBody PROCINLINE:<{ + NEWC + 3513996288 PUSHINT + SWAP + 32 STU + 64 STU + ROT + STSLICER + OVER + ISNULL + NOT + IF:<{ + NEWC + s0 s2 XCHG + __tact_not_null INLINECALLDICT + s1 s2 XCHG + STSLICER + ENDC + SWAP + TRUE + __tact_store_bool INLINECALLDICT + STREF + }>ELSE<{ + NIP + FALSE + __tact_store_bool INLINECALLDICT + }> + ENDC + }> + $JettonMinter$_fun_getJettonWalletInit PROCINLINE:<{ + __tact_context_sys GETGLOB + MYADDR + s1 s2 XCHG + $JettonWallet$_init_child INLINECALLDICT + }> + $JettonMinter$_fun_getJettonWalletByOwner PROCINLINE:<{ + $JettonMinter$_fun_getJettonWalletInit INLINECALLDICT + $global_contractAddress INLINECALLDICT + }> + $JettonMasterState$_constructor_totalSupply_mintable_adminAddress_jettonContent_jettonWalletCode PROCINLINE:<{ + }> + $JettonMinter$_fun_get_jetton_data PROCREF:<{ + __tact_context_sys GETGLOB + MYADDR + MYADDR + $JettonWallet$_init_child INLINECALLDICT + $StateInit$_get_code INLINECALLDICT + s4 s3 s(-2) PU2XC + s4 s3 s(-2) PU2XC + $JettonMasterState$_constructor_totalSupply_mintable_adminAddress_jettonContent_jettonWalletCode INLINECALLDICT + }> + $JettonMinter$_fun_get_wallet_address PROCREF:<{ + $JettonMinter$_fun_getJettonWalletByOwner INLINECALLDICT + }> + $JettonMinter$_fun_owner PROCREF:<{ + OVER + }> + $SendParameters$_constructor_to_value_bounce_mode_body PROCINLINE:<{ + s2 s4 XCHG + s2 s3 XCHG + PUSHNULL + PUSHNULL + }> + $TokenExcesses$_constructor_query_id PROCINLINE:<{ + }> + $SendParameters$_constructor_to_value_mode_body PROCINLINE:<{ + TRUE + 4 -ROLL + PUSHNULL + PUSHNULL + }> + $SendParameters$_constructor_to_value_bounce_mode_body_code_data PROCINLINE:<{ + s4 s6 XCHG + s4 s5 XCHG + }> + $TokenTransferInternal$_constructor_query_id_amount_from_response_destination_forward_ton_amount_forward_payload PROCINLINE:<{ + }> + $JettonMinter$_internal_binary_TokenBurnNotification PROCINLINE:<{ + s4 s7 XCHG + s3 s6 XCHG + s5 s7 s7 XCHG3 + $JettonMinter$_fun_getJettonWalletByOwner INLINECALLDICT + __tact_context_get_sender INLINECALLDICT + __tact_slice_eq_bits INLINECALLDICT + 74 THROWIFNOT + s3 s4 XCHG2 + SUB + 0 PUSHINT + FALSE + 66 PUSHINT + s0 s7 XCHG + $TokenExcesses$_constructor_query_id INLINECALLDICT + $TokenExcesses$_store_cell INLINECALLDICT + s4 s8 XCHG + s1 s3 s0 XCHG3 + s1 s7 XCHG + $SendParameters$_constructor_to_value_bounce_mode_body INLINECALLDICT + $global_send INLINECALLDICT + DROP + s3 s0 s0 XCHG3 + }> + $JettonMinter$_internal_binary_CustomChangeOwner PROCINLINE:<{ + NIP + __tact_context_get_sender INLINECALLDICT + s1 s3 XCHG + __tact_slice_eq_bits INLINECALLDICT + 73 THROWIFNOT + }> + $JettonMinter$_internal_binary_TokenUpdateContent PROCINLINE:<{ + NIP + __tact_context_get_sender INLINECALLDICT + s2 s(-1) PUXC + __tact_slice_eq_bits INLINECALLDICT + 73 THROWIFNOT + }> + $JettonMinter$_internal_binary_ProvideWalletAddress PROCINLINE:<{ + __tact_context_get INLINECALLDICT + $Context$_get_value INLINECALLDICT + 6705600 PUSHINT + GEQ + 75 THROWIFNOT + PUSHNULL + s2 PUSH + REWRITESTDADDR + $StdAddress$_get_workchain INLINECALLDICT + b{00} PUSHSLICE + SWAP + 0 EQINT + IF:<{ + DROP + __tact_context_sys GETGLOB + MYADDR + s4 s(-1) PUXC + $JettonWallet$_init_child INLINECALLDICT + $global_contractAddress INLINECALLDICT + }> + s0 s2 XCHG + IF:<{ + DROP + }>ELSE<{ + s2 POP + }> + __tact_context_get_sender INLINECALLDICT + s4 s7 XCHG + s3 s6 XCHG + s5 s1 s7 XCHG3 + 0 PUSHINT + s2 s6 XCHG2 + 64 PUSHINT + s0 s8 XCHG + $JettonMinter$_fun_takeWalletBody INLINECALLDICT + s3 s7 XCHG + s5 s6 s0 XCHG3 + $SendParameters$_constructor_to_value_mode_body INLINECALLDICT + $global_send INLINECALLDICT + DROP + s3 s1 s3 XCHG3 + }> + $JettonMinter$_internal_binary_Mint PROCINLINE:<{ + __tact_context_get_sender INLINECALLDICT + s5 s(-1) PUXC + __tact_slice_eq_bits INLINECALLDICT + 73 THROWIFNOT + 3688 PUSHINT + s6 PUSH + THROWANYIFNOT + s6 s1 XCPU + ADD + s0 s4 XCHG + s3 s5 XCHG + s0 s5 s6 XCHG3 + $JettonMinter$_fun_getJettonWalletInit INLINECALLDICT + 2DUP + $global_contractAddress INLINECALLDICT + 0 PUSHINT + TRUE + 64 PUSHINT + MYADDR + 1 PUSHINT + $global_emptySlice INLINECALLDICT + s10 PUSH + s5 s15 XCHG + s4 s14 XCHG + -ROT + $TokenTransferInternal$_constructor_query_id_amount_from_response_destination_forward_ton_amount_forward_payload INLINECALLDICT + $TokenTransferInternal$_store_cell INLINECALLDICT + s6 s5 s0 XCHG3 + s4 s10 XCHG + s3 s9 XCHG + s0 s10 s9 XCHG3 + $SendParameters$_constructor_to_value_bounce_mode_body_code_data INLINECALLDICT + $global_send INLINECALLDICT + DROP + s0 s0 s3 XCHG3 + }> + $JettonMinter$_receive_binary_bounce_TokenTransferInternal PROCINLINE:<{ + NIP + s1 s4 XCHG + SUB + s0 s3 XCHG + }> + %get_jetton_data PROC:<{ + $JettonMinter$_contract_load INLINECALLDICT + $JettonMinter$_fun_get_jetton_data INLINECALLDICT + 4 5 BLKDROP2 + $JettonMasterState$_to_external INLINECALLDICT + }> + %get_wallet_address PROC:<{ + __tact_verify_address INLINECALLDICT + $JettonMinter$_contract_load INLINECALLDICT + 4 ROLL + $JettonMinter$_fun_get_wallet_address INLINECALLDICT + 4 1 BLKDROP2 + }> + %owner PROC:<{ + $JettonMinter$_contract_load INLINECALLDICT + $JettonMinter$_fun_owner INLINECALLDICT + 4 1 BLKDROP2 + }> + lazy_deployment_completed PROC:<{ + c4 PUSH + CTOS + 1 LDI + SWAP + }> + $JettonMinter$_contract_router_internal PROCREF:<{ + SWAP + IFJMP:<{ + 32 PUSHINT + SDSKIPFIRST + 0 PUSHINT + OVER + SBITS + 31 GTINT + IF:<{ + DROP + DUP + 32 PLDU + }> + 395134233 PUSHINT + EQUAL + IFJMP:<{ + $TokenTransferInternal$_load_bounced INLINECALLDICT + 1 2 BLKDROP2 + $JettonMinter$_receive_binary_bounce_TokenTransferInternal INLINECALLDICT + TRUE + }> + DROP + TRUE + }> + 0 PUSHINT + OVER + SBITS + 31 GTINT + IF:<{ + DROP + DUP + 32 PLDU + }> + DUP + 2078119902 PUSHINT + EQUAL + IFJMP:<{ + DROP + $TokenBurnNotification$_load INLINECALLDICT + 1 4 BLKDROP2 + $JettonMinter$_internal_binary_TokenBurnNotification INLINECALLDICT + TRUE + }> + DUP + 3 EQINT + IFJMP:<{ + DROP + $CustomChangeOwner$_load INLINECALLDICT + 1 2 BLKDROP2 + $JettonMinter$_internal_binary_CustomChangeOwner INLINECALLDICT + TRUE + }> + DUP + 4 EQINT + IFJMP:<{ + DROP + $TokenUpdateContent$_load INLINECALLDICT + NIP + $JettonMinter$_internal_binary_TokenUpdateContent INLINECALLDICT + TRUE + }> + DUP + 745978227 PUSHINT + EQUAL + IFJMP:<{ + DROP + $ProvideWalletAddress$_load INLINECALLDICT + 1 3 BLKDROP2 + $JettonMinter$_internal_binary_ProvideWalletAddress INLINECALLDICT + TRUE + }> + 21 EQINT + IFJMP:<{ + $Mint$_load INLINECALLDICT + 1 3 BLKDROP2 + $JettonMinter$_internal_binary_Mint INLINECALLDICT + TRUE + }> + DROP + FALSE + }> + recv_internal PROC:<{ + SWAP + CTOS + 4 LDU + SWAP + 1 PUSHINT + AND + NEGATE + SWAP + LDMSGADDR + SWAP + __tact_verify_address INLINECALLDICT + s0 s4 s2 PUXCPU + s0 s3 XCHG + 4 TUPLE + __tact_context SETGLOB + s0 s2 XCHG + __tact_context_sender SETGLOB + $JettonMinter$_contract_load INLINECALLDICT + 2 4 BLKSWAP + $JettonMinter$_contract_router_internal INLINECALLDICT + 130 THROWIFNOT + $JettonMinter$_contract_store INLINECALLDICT + }> +}END>c diff --git a/src/test/e2e/decompile-with-debug-info.spec.ts b/src/test/e2e/decompile-with-debug-info.spec.ts new file mode 100644 index 0000000..7c5f15f --- /dev/null +++ b/src/test/e2e/decompile-with-debug-info.spec.ts @@ -0,0 +1,29 @@ +import {describe, expect, test} from "vitest" +import {Cell} from "@ton/core" +import {AssemblyWriter} from "../../printer/assembly-writer" +import {debugSymbols} from "../../utils/known-methods" +import {obtainSourceMap} from "../../decompiler/source-map" +import {disassembleRoot} from "../../decompiler/disasm" + +describe("disassemble", () => { + test(`should decompile JettonMinter with debug info`, async () => { + const code = + "te6ccgECHAEABngAART/APSkE/S88sgLAQIBYgIDAt7QAdDTAwFxsKMB+kABINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIVFBTA28E+GEC+GLbPFUT2zzy4ILI+EMBzH8BygBVMFBD+gLKAFgg10mBAQu68uCIINcLCiCDCboBgQT/urHy4IjPFszJ7VQYBAIBIBARA/YBjjaAINchcCHXScIflTAg1wsf3oIQF41FGbqOGdMfAYIQF41FGbry4IHTP/oAWWwSMRShA3/gMH/gcCHXScIflTAg1wsf3iCCEHvdl9664wIgwAPjAiDABI4XMNMfAcAE8uCB1AExMfhCUiDHBfLgSX/gIIIQLHa5c7oFBgcBqDDTHwGCEHvdl9668uCB0z/6APpAASDXSYEBC7ry4Igg1wsKIIMJugGBBP+6sfLgiAH6QAEg10mBAQu68uCIINcLCiCDCboBgQT/urHy4IgUQzBsFAgAbDDTHwHAA/LggdM/+kABINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIEmwSMfhCE8cF8uBJfwLsjrgw0x8BghAsdrlzuvLggdM/+kABINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIAdIAVSBsE9s8f+DAFY600x8BwBXy4IHTP4EBAdcA+kABINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIQzBsE9s8f+AwcAkKAvYQRxA2RXf4Q/goEts8cFnIcAHLAXMBywFwAcsAEszMyfkAyHIBywFwAcsAEsoHy//J0CDXSYEBC7ry4Igg1wsKIIMJugGBBP+6sfLgiPhCxwXy4EpQNKFwcIBCB8gBghDVMnbbWMsfyz/JEEhBMBcQJBAjbW3bPDBDAH8bDgL0+EFvJBNfA4IIZlHAvvLgS20i+kQwiwIBwACOyTD4Q/goUkDbPHBZyHABywFzAcsBcAHLABLMzMn5AMhyAcsBcAHLABLKB8v/ydAg10mBAQu68uCIINcLCiCDCboBgQT/urHy4IjeApEwkTLi+EIQRxA2RRdwUCaAQAgbCwP2+EJSUMcF8uBJgQ5oJvL0UWGgBBA1QFb4Q/goEts8XHBZyHABywFzAcsBcAHLABLMzMn5AMhyAcsBcAHLABLKB8v/ydAg10mBAQu68uCIINcLCiCDCboBgQT/urHy4Ihwf4BA+ChxyMnQKhBfEE5ZyFVQ2zzJRlAQShA5GwwNAXbIghDRc1QAAcsfyz9YzxYhbrOOEcgCIG7y0IASzxbJAX8BygDMlTFwAcoA4skQN0Vgf1UwbW3bPDBDEw4AvIIQF41FGVAHyx8Vyz9QA/oCASDXSYEBC7ry4Igg1wsKIIMJugGBBP+6sfLgiM8WASBulTBwAcsBjh0g10mBAQu68uCIINcLCiCDCboBgQT/urHy4IjPFuIB+gIBzxYBFkCpEEYQRds8MEADDgHIyHEBygFQBwHKAHABygJQBSDXSYEBC7ry4Igg1wsKIIMJugGBBP+6sfLgiM8WUAP6AnABymgjbrORf5MkbrPilzMzAXABygDjDSFus5x/AcoAASBu8tCAAcyVMXABygDiyQH7CA8AmH8BygDIcAHKAHABygAkbrOdfwHKAAQgbvLQgFAEzJY0A3ABygDiJG6znX8BygAEIG7y0IBQBMyWNANwAcoA4nABygACfwHKAALJWMwCEb4o7tnm2eNiDBgSAgEgExQAAiECAWYVFgARuCvu1E0NIAAYAkutvJBrpMCAhd15cEQQa4WFEEGE3QDAgn/dWPlwRG2eKoHtnjYgwBgXAhGvFu2ebZ42IsAYGQGO+EP4KBLbPHBZyHABywFzAcsBcAHLABLMzMn5AMhyAcsBcAHLABLKB8v/ydAg10mBAQu68uCIINcLCiCDCboBgQT/urHy4IgbAbbtRNDUAfhj0gABjij6ANIA+kABINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIAdRVMGwU4PpAASDXSYEBC7ry4Igg1wsKIIMJugGBBP+6sfLgiAHUWQLRAds8GgEe+EP4KPgo2zwwVGRAVGRAGwAIcAJ/AgDSAtD0BDBtAYEOtQGAEPQPb6Hy4IcBgQ61IgKAEPQXyAHI9ADJAcxwAcoAQANZINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIzxYBINdJgQELuvLgiCDXCwoggwm6AYEE/7qx8uCIzxbJ" + const source = Cell.fromBase64(code) + + const program = disassembleRoot(source, { + computeRefs: true, + }) + + const sourceMap = await obtainSourceMap( + __dirname + "/__testdata__/Jetton_JettonMinter.code.fif", + ) + const res = AssemblyWriter.write(program, { + useAliases: false, + outputBitcodeAfterInstruction: true, + debugSymbols: debugSymbols, + sourceMap: sourceMap, + }) + expect(res).toMatchSnapshot() + }) +}) diff --git a/src/test/e2e/utils.ts b/src/test/e2e/utils.ts index d940af7..a3799b6 100644 --- a/src/test/e2e/utils.ts +++ b/src/test/e2e/utils.ts @@ -38,9 +38,12 @@ export async function compileFiftBackAndCompare( raw: boolean = false, ): Promise { const result = await compileFift(content) - if (!result.ok) { + if (result.status === "error") { fail(`cannot compile boc:\n${result.log}`) } + if (result.status === "source_map") { + return + } const resultBase64 = result.output.toString("base64") const beforeBase64 = before.toString("base64") diff --git a/src/test/e2e/verifier-contracts.spec.ts b/src/test/e2e/verifier-contracts.spec.ts index 881e804..779560b 100644 --- a/src/test/e2e/verifier-contracts.spec.ts +++ b/src/test/e2e/verifier-contracts.spec.ts @@ -46,7 +46,7 @@ describe("tact contracts", () => { const withoutRefs = decompileAll(source, debugSymbols, false) const result = await compileFift(withoutRefs) - if (!result.ok) { + if (result.status === "error") { fail(`cannot compile boc:\n${result.log}`) } })