From 04a1d87e06314e334af4b776412af9f2717568fc Mon Sep 17 00:00:00 2001 From: Gusarich Date: Tue, 5 Mar 2024 23:18:10 +0300 Subject: [PATCH 1/4] implement implicit init --- .../feature-implicit-init.spec.ts.snap | 109 +++++ src/test/feature-implicit-init.spec.ts | 48 ++ src/test/features/implicit-init.tact | 13 + .../output/implicit-init_MyContract.abi | 1 + .../output/implicit-init_MyContract.code.boc | Bin 0 -> 690 bytes .../output/implicit-init_MyContract.code.fc | 127 +++++ .../output/implicit-init_MyContract.code.fif | 382 +++++++++++++++ .../implicit-init_MyContract.code.rev.fif | 347 ++++++++++++++ .../implicit-init_MyContract.headers.fc | 70 +++ .../output/implicit-init_MyContract.md | 61 +++ .../output/implicit-init_MyContract.pkg | 1 + .../output/implicit-init_MyContract.stdlib.fc | 111 +++++ .../implicit-init_MyContract.storage.fc | 88 ++++ .../output/implicit-init_MyContract.ts | 442 ++++++++++++++++++ src/types/resolveDescriptors.ts | 12 +- tact.config.json | 22 +- 16 files changed, 1825 insertions(+), 9 deletions(-) create mode 100644 src/test/__snapshots__/feature-implicit-init.spec.ts.snap create mode 100644 src/test/feature-implicit-init.spec.ts create mode 100644 src/test/features/implicit-init.tact create mode 100644 src/test/features/output/implicit-init_MyContract.abi create mode 100644 src/test/features/output/implicit-init_MyContract.code.boc create mode 100644 src/test/features/output/implicit-init_MyContract.code.fc create mode 100644 src/test/features/output/implicit-init_MyContract.code.fif create mode 100644 src/test/features/output/implicit-init_MyContract.code.rev.fif create mode 100644 src/test/features/output/implicit-init_MyContract.headers.fc create mode 100644 src/test/features/output/implicit-init_MyContract.md create mode 100644 src/test/features/output/implicit-init_MyContract.pkg create mode 100644 src/test/features/output/implicit-init_MyContract.stdlib.fc create mode 100644 src/test/features/output/implicit-init_MyContract.storage.fc create mode 100644 src/test/features/output/implicit-init_MyContract.ts diff --git a/src/test/__snapshots__/feature-implicit-init.spec.ts.snap b/src/test/__snapshots__/feature-implicit-init.spec.ts.snap new file mode 100644 index 000000000..d1490279c --- /dev/null +++ b/src/test/__snapshots__/feature-implicit-init.spec.ts.snap @@ -0,0 +1,109 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`feature-send should deploy 1`] = ` +[ + { + "$seq": 0, + "events": [ + { + "$type": "deploy", + }, + { + "$type": "received", + "message": { + "body": { + "type": "known", + "value": { + "$$type": "Deploy", + "queryId": 0n, + }, + }, + "bounce": true, + "from": "@treasure(treasure)", + "to": "kQDHqMJCGk6QhukOD8ZKGLou9KVeRAM3pGOa_JYP47mob9WO", + "type": "internal", + "value": "1", + }, + }, + { + "$type": "processed", + "gasUsed": 7147n, + }, + { + "$type": "sent", + "messages": [ + { + "body": { + "type": "known", + "value": { + "$$type": "DeployOk", + "queryId": 0n, + }, + }, + "bounce": false, + "from": "kQDHqMJCGk6QhukOD8ZKGLou9KVeRAM3pGOa_JYP47mob9WO", + "to": "@treasure(treasure)", + "type": "internal", + "value": "0.991657", + }, + ], + }, + ], + }, +] +`; + +exports[`feature-send should increment counter 1`] = ` +[ + { + "$seq": 1, + "events": [ + { + "$type": "received", + "message": { + "body": { + "text": "increment", + "type": "text", + }, + "bounce": true, + "from": "@treasure(treasure)", + "to": "kQDHqMJCGk6QhukOD8ZKGLou9KVeRAM3pGOa_JYP47mob9WO", + "type": "internal", + "value": "1", + }, + }, + { + "$type": "processed", + "gasUsed": 3746n, + }, + ], + }, + { + "$seq": 2, + "events": [ + { + "$type": "storage-charged", + "amount": "0.000000004", + }, + { + "$type": "received", + "message": { + "body": { + "text": "increment", + "type": "text", + }, + "bounce": true, + "from": "@treasure(treasure)", + "to": "kQDHqMJCGk6QhukOD8ZKGLou9KVeRAM3pGOa_JYP47mob9WO", + "type": "internal", + "value": "1", + }, + }, + { + "$type": "processed", + "gasUsed": 3746n, + }, + ], + }, +] +`; diff --git a/src/test/feature-implicit-init.spec.ts b/src/test/feature-implicit-init.spec.ts new file mode 100644 index 000000000..6a67575e2 --- /dev/null +++ b/src/test/feature-implicit-init.spec.ts @@ -0,0 +1,48 @@ +import { toNano } from '@ton/core'; +import { ContractSystem } from '@tact-lang/emulator'; +import { __DANGER_resetNodeId } from '../grammar/ast'; +import { MyContract } from './features/output/implicit-init_MyContract'; + +describe('feature-send', () => { + beforeEach(() => { + __DANGER_resetNodeId(); + }); + it('should deploy', async () => { + // Init + const system = await ContractSystem.create(); + const treasure = system.treasure('treasure'); + const contract = system.open(await MyContract.fromInit()); + const tracker = system.track(contract.address); + await contract.send( + treasure, + { value: toNano('1') }, + { $$type: 'Deploy', queryId: 0n } + ); + await system.run(); + expect(await contract.getGetCounter()).toBe(0n); + expect(tracker.collect()).toMatchSnapshot(); + }); + it('should increment counter', async () => { + // Init + const system = await ContractSystem.create(); + const treasure = system.treasure('treasure'); + const contract = system.open(await MyContract.fromInit()); + await contract.send( + treasure, + { value: toNano('1') }, + { $$type: 'Deploy', queryId: 0n } + ); + await system.run(); + + // Test + expect(await contract.getGetCounter()).toBe(0n); + const tracker = system.track(contract); + await contract.send(treasure, { value: toNano('1') }, 'increment'); + await system.run(); + expect(await contract.getGetCounter()).toBe(1n); + await contract.send(treasure, { value: toNano('1') }, 'increment'); + await system.run(); + expect(await contract.getGetCounter()).toBe(2n); + expect(tracker.collect()).toMatchSnapshot(); + }); +}); diff --git a/src/test/features/implicit-init.tact b/src/test/features/implicit-init.tact new file mode 100644 index 000000000..2bdb96e53 --- /dev/null +++ b/src/test/features/implicit-init.tact @@ -0,0 +1,13 @@ +import "@stdlib/deploy"; + +contract MyContract with Deployable { + counter: Int = 0; + + receive("increment") { + self.counter += 1; + } + + get fun getCounter(): Int { + return self.counter; + } +} \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.abi b/src/test/features/output/implicit-init_MyContract.abi new file mode 100644 index 000000000..cf83b6068 --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.abi @@ -0,0 +1 @@ +{"name":"MyContract","types":[{"name":"StateInit","header":null,"fields":[{"name":"code","type":{"kind":"simple","type":"cell","optional":false}},{"name":"data","type":{"kind":"simple","type":"cell","optional":false}}]},{"name":"Context","header":null,"fields":[{"name":"bounced","type":{"kind":"simple","type":"bool","optional":false}},{"name":"sender","type":{"kind":"simple","type":"address","optional":false}},{"name":"value","type":{"kind":"simple","type":"int","optional":false,"format":257}},{"name":"raw","type":{"kind":"simple","type":"slice","optional":false}}]},{"name":"SendParameters","header":null,"fields":[{"name":"bounce","type":{"kind":"simple","type":"bool","optional":false}},{"name":"to","type":{"kind":"simple","type":"address","optional":false}},{"name":"value","type":{"kind":"simple","type":"int","optional":false,"format":257}},{"name":"mode","type":{"kind":"simple","type":"int","optional":false,"format":257}},{"name":"body","type":{"kind":"simple","type":"cell","optional":true}},{"name":"code","type":{"kind":"simple","type":"cell","optional":true}},{"name":"data","type":{"kind":"simple","type":"cell","optional":true}}]},{"name":"Deploy","header":2490013878,"fields":[{"name":"queryId","type":{"kind":"simple","type":"uint","optional":false,"format":64}}]},{"name":"DeployOk","header":2952335191,"fields":[{"name":"queryId","type":{"kind":"simple","type":"uint","optional":false,"format":64}}]},{"name":"FactoryDeploy","header":1829761339,"fields":[{"name":"queryId","type":{"kind":"simple","type":"uint","optional":false,"format":64}},{"name":"cashback","type":{"kind":"simple","type":"address","optional":false}}]}],"receivers":[{"receiver":"internal","message":{"kind":"text","text":"increment"}},{"receiver":"internal","message":{"kind":"typed","type":"Deploy"}}],"getters":[{"name":"getCounter","arguments":[],"returnType":{"kind":"simple","type":"int","optional":false,"format":257}}],"errors":{"2":{"message":"Stack undeflow"},"3":{"message":"Stack overflow"},"4":{"message":"Integer overflow"},"5":{"message":"Integer out of expected range"},"6":{"message":"Invalid opcode"},"7":{"message":"Type check error"},"8":{"message":"Cell overflow"},"9":{"message":"Cell underflow"},"10":{"message":"Dictionary error"},"13":{"message":"Out of gas error"},"32":{"message":"Method ID not found"},"34":{"message":"Action is invalid or not supported"},"37":{"message":"Not enough TON"},"38":{"message":"Not enough extra-currencies"},"128":{"message":"Null reference exception"},"129":{"message":"Invalid serialization prefix"},"130":{"message":"Invalid incoming message"},"131":{"message":"Constraints error"},"132":{"message":"Access denied"},"133":{"message":"Contract stopped"},"134":{"message":"Invalid argument"},"135":{"message":"Code of a contract was not found"},"136":{"message":"Invalid address"},"137":{"message":"Masterchain support is not enabled for this contract"}},"interfaces":["org.ton.introspection.v0","org.ton.abi.ipfs.v0","org.ton.deploy.lazy.v0","org.ton.debug.v0","org.ton.chain.workchain.v0"]} \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.code.boc b/src/test/features/output/implicit-init_MyContract.code.boc new file mode 100644 index 0000000000000000000000000000000000000000..cde67207e13f2b9282a72a991f3291ef7f625c93 GIT binary patch literal 690 zcmdn`ZcY&+lOQ7l(=rA|k^c-|mI!~@^XUXPBNJm16EoAi3yc>oGcy)$Sj_m#fl=YQ zXCou`u1^m-6s~h~DKxVD-}UK2XEP^ABqSi1IiKZ6BGZqg+cuH6Z9Y9{I`PAq@k~AA zDF#NyMn=Z-3@6`)@USp3MsRR4eS5p;?Qh0O2K5gL6t8<8lAme-G*SMZLX*IhtQp&O z^{p_tEYAq#e0tD$*`Cqx1dzY}Cx3XvY5CLkCx19G7UbTxsef>Qp-=lKW7CHtKdvha zz5V+>y82Cp@!s8Hx}t)6D^?1vyYMNw>RV{hx?NM2)ZaFIFwx)osxB1a@V`E032*YDu#k|dPz+nKki}B1j-w`|71r&nI7)+irC-U~$d`KjB@+mM+cdpOz9;`gH$39d`pi7Oox41w3zxW}apb zJ@I5)M1dc3)#SaOR&2Uw@v5r&z-o&Wpsr0XPlsjR%u9E?baqqEU6BclPH$Z6GcX!HF!-SXOdsHM(Rtg3kAX>nfvJE&aKrlDfhHym3<(USoAMqzhfQZo zH(vDVtJu|$E6>@(!`zJ1ibIaJ9GxC4>MoMf+8VaKxm;D;Jv5Y^<=C?D_7amV&8f;W F6aW-`CDH%@ literal 0 HcmV?d00001 diff --git a/src/test/features/output/implicit-init_MyContract.code.fc b/src/test/features/output/implicit-init_MyContract.code.fc new file mode 100644 index 000000000..78771130c --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.code.fc @@ -0,0 +1,127 @@ +#pragma version =0.4.3; +#pragma allow-post-modification; +#pragma compute-asm-ltr; + +#include "implicit-init_MyContract.headers.fc"; +#include "implicit-init_MyContract.stdlib.fc"; +#include "implicit-init_MyContract.storage.fc"; + +;; +;; Contract MyContract functions +;; + +(int) $MyContract$_contract_init() impure inline_ref { + var (($self'counter)) = (0); + return ($self'counter); +} + +((int), int) $MyContract$_fun_getCounter((int) $self) impure inline_ref { + var (($self'counter)) = $self; + return (($self'counter), $self'counter); +} + +;; +;; Receivers of a Contract MyContract +;; + +((int), ()) $MyContract$_internal_text_c4f8d72312edfdef5b7bec7833bdbb162d1511bd78a912aed0f2637af65572ae((int) $self) impure inline { + var ($self'counter) = $self; + $self'counter = $self'counter + 1; + return (($self'counter), ()); +} + +(((int)), ()) $MyContract$_internal_binary_Deploy((int) $self, (int) $deploy) impure inline { + var ($self'counter) = $self; + var ($deploy'queryId) = $deploy; + ($self'counter)~$MyContract$_fun_notify($DeployOk$_store_cell($DeployOk$_constructor_queryId($deploy'queryId))); + return (($self'counter), ()); +} + +;; +;; Get methods of a Contract MyContract +;; + +_ %getCounter() method_id(103307) { + var self = $MyContract$_contract_load(); + var res = self~$MyContract$_fun_getCounter(); + return res; +} + +_ supported_interfaces() method_id { + return ( + "org.ton.introspection.v0"H >> 128, + "org.ton.abi.ipfs.v0"H >> 128, + "org.ton.deploy.lazy.v0"H >> 128, + "org.ton.debug.v0"H >> 128, + "org.ton.chain.workchain.v0"H >> 128 + ); +} + +_ get_abi_ipfs() method_id { + return "ipfs://QmUMNpuudc6g5LXLYu1TqFHXUkx7rQtuUPpLjexwCKH6R9"; +} + +_ lazy_deployment_completed() method_id { + return get_data().begin_parse().load_int(1); +} + +;; +;; Routing of a Contract MyContract +;; + +((int), int) $MyContract$_contract_router_internal((int) self, int msg_bounced, slice in_msg) impure inline_ref { + ;; Handle bounced messages + if (msg_bounced) { + return (self, true); + } + + ;; Parse incoming message + int op = 0; + if (slice_bits(in_msg) >= 32) { + op = in_msg.preload_uint(32); + } + + + ;; Receive Deploy message + if (op == 2490013878) { + var msg = in_msg~$Deploy$_load(); + self~$MyContract$_internal_binary_Deploy(msg); + return (self, true); + } + + ;; Text Receivers + if (op == 0) { + var text_op = slice_hash(in_msg); + + ;; Receive "increment" message + if (text_op == 0xc4f8d72312edfdef5b7bec7833bdbb162d1511bd78a912aed0f2637af65572ae) { + self~$MyContract$_internal_text_c4f8d72312edfdef5b7bec7833bdbb162d1511bd78a912aed0f2637af65572ae(); + return (self, true); + } + } + + return (self, false); +} + +() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { + + ;; Context + var cs = in_msg_cell.begin_parse(); + var msg_flags = cs~load_uint(4); + var msg_bounced = -(msg_flags & 1); + slice msg_sender_addr = __tact_verify_address(cs~load_msg_addr()); + __tact_context = (msg_bounced, msg_sender_addr, msg_value, cs); + __tact_context_sender = msg_sender_addr; + + ;; Load contract data + var self = $MyContract$_contract_load(); + + ;; Handle operation + int handled = self~$MyContract$_contract_router_internal(msg_bounced, in_msg); + + ;; Throw if not handled + throw_unless(130, handled); + + ;; Persist state + $MyContract$_contract_store(self); +} diff --git a/src/test/features/output/implicit-init_MyContract.code.fif b/src/test/features/output/implicit-init_MyContract.code.fif new file mode 100644 index 000000000..ae68f2c1c --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.code.fif @@ -0,0 +1,382 @@ +PROGRAM{ + DECLPROC __tact_verify_address + DECLPROC __tact_store_address + DECLPROC __tact_my_balance + DECLPROC __tact_not_null + DECLPROC __tact_context_get + DECLPROC __tact_context_get_sender + DECLPROC __tact_store_bool + DECLPROC $Deploy$_load + DECLPROC $DeployOk$_store + DECLPROC $DeployOk$_store_cell + DECLPROC $MyContract$_store + DECLPROC $MyContract$_load + DECLPROC $StateInit$_not_null + DECLPROC $MyContract$_contract_init + DECLPROC $MyContract$_contract_load + DECLPROC $MyContract$_contract_store + DECLPROC $global_send + DECLPROC $MyContract$_fun_getCounter + DECLPROC $SendParameters$_constructor_bounce_to_value_mode_body_code_data + DECLPROC $MyContract$_fun_forward + DECLPROC $MyContract$_fun_notify + DECLPROC $DeployOk$_constructor_queryId + DECLPROC $MyContract$_internal_text_c4f8d72312edfdef5b7bec7833bdbb162d1511bd78a912aed0f2637af65572ae + DECLPROC $MyContract$_internal_binary_Deploy + 103307 DECLMETHOD %getCounter + 113617 DECLMETHOD supported_interfaces + 121275 DECLMETHOD get_abi_ipfs + 115390 DECLMETHOD lazy_deployment_completed + DECLPROC $MyContract$_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 + 1279 PUSHINT + EQUAL + 137 THROWIF + 10 PUSHPOW2 + EQUAL + 136 THROWIFNOT + }> + __tact_store_address PROCINLINE:<{ + __tact_verify_address INLINECALLDICT + STSLICER + }> + __tact_my_balance PROCINLINE:<{ + BALANCE + FIRST + }> + __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 + }> + $Deploy$_load PROCINLINE:<{ + 32 LDU + SWAP + 2490013878 PUSHINT + EQUAL + 129 THROWIFNOT + 64 LDU + SWAP + }> + $DeployOk$_store PROCINLINE:<{ + 2952335191 PUSHINT + ROT + 32 STU + 64 STU + }> + $DeployOk$_store_cell PROCINLINE:<{ + NEWC + SWAP + $DeployOk$_store INLINECALLDICT + ENDC + }> + $MyContract$_store PROCINLINE:<{ + SWAP + 257 PUSHINT + STIX + }> + $MyContract$_load PROCINLINE:<{ + 257 PUSHINT + LDIX + SWAP + }> + $StateInit$_not_null PROCINLINE:<{ + DUP + ISNULL + 128 THROWIF + 2 UNTUPLE + }> + $MyContract$_contract_init PROCREF:<{ + 0 PUSHINT + }> + $MyContract$_contract_load PROCREF:<{ + c4 PUSH + CTOS + LDREF + SWAP + __tact_context_sys SETGLOB + 1 LDI + SWAP + IFJMP:<{ + $MyContract$_load INLINECALLDICT + NIP + }> + DROP + MYADDR + 11 PLDU + 10 PUSHPOW2 + EQUAL + 137 THROWIFNOT + $MyContract$_contract_init INLINECALLDICT + }> + $MyContract$_contract_store PROCINLINE:<{ + NEWC + __tact_context_sys GETGLOB + SWAP + STREF + TRUE + SWAP + 1 STI + SWAP + $MyContract$_store INLINECALLDICT + ENDC + c4 POP + }> + $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 + STGRAMS + 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 + SENDRAWMSG + }> + $MyContract$_fun_getCounter PROCREF:<{ + DUP + }> + $SendParameters$_constructor_bounce_to_value_mode_body_code_data PROCINLINE:<{ + }> + $MyContract$_fun_forward PROCREF:<{ + PUSHNULL + PUSHNULL + s2 PUSH + ISNULL + NOT + IF:<{ + 2DROP + $StateInit$_not_null INLINECALLDICT + SWAP + }>ELSE<{ + s2 POP + }> + s2 s4 XCHG + 0 PUSHINT + s0 s3 XCHG + s0 s4 XCHG + 66 PUSHINT + s2 s3 XCHG2 + $SendParameters$_constructor_bounce_to_value_mode_body_code_data INLINECALLDICT + $global_send INLINECALLDICT + }> + $MyContract$_fun_notify PROCINLINE:<{ + __tact_context_get_sender INLINECALLDICT + SWAP + FALSE + PUSHNULL + $MyContract$_fun_forward INLINECALLDICT + }> + $DeployOk$_constructor_queryId PROCINLINE:<{ + }> + $MyContract$_internal_text_c4f8d72312edfdef5b7bec7833bdbb162d1511bd78a912aed0f2637af65572ae PROCINLINE:<{ + INC + }> + $MyContract$_internal_binary_Deploy PROCINLINE:<{ + $DeployOk$_constructor_queryId INLINECALLDICT + $DeployOk$_store_cell INLINECALLDICT + $MyContract$_fun_notify INLINECALLDICT + }> + %getCounter PROC:<{ + $MyContract$_contract_load INLINECALLDICT + $MyContract$_fun_getCounter INLINECALLDICT + NIP + }> + supported_interfaces PROC:<{ + 123515602279859691144772641439386770278 PUSHINT + 209801025412363888721030803524359905849 PUSHINT + 42980537499636128163026532310500881091 PUSHINT + 36993126140238121407019133875791708966 PUSHINT + 209474421377847335869795010607481022628 PUSHINT + }> + get_abi_ipfs PROC:<{ + x{697066733a2f2f516d554d4e70757564633667354c584c5975315471464858556b7837725174755550704c6a657877434b48365239} PUSHSLICE + }> + lazy_deployment_completed PROC:<{ + c4 PUSH + CTOS + 1 LDI + SWAP + }> + $MyContract$_contract_router_internal PROCREF:<{ + c2 SAVE + SAMEALTSAVE + SWAP + IFJMP:<{ + DROP + TRUE + }> + 0 PUSHINT + OVER + SBITS + 31 GTINT + IF:<{ + DROP + DUP + 32 PLDU + }> + DUP + 2490013878 PUSHINT + EQUAL + IFJMP:<{ + DROP + $Deploy$_load INLINECALLDICT + NIP + $MyContract$_internal_binary_Deploy INLINECALLDICT + TRUE + }> + 0 EQINT + IF:<{ + HASHSU + 89092981215441470209245890604563109773385607357076622359718516871332286001838 PUSHINT + EQUAL + IFJMP:<{ + $MyContract$_internal_text_c4f8d72312edfdef5b7bec7833bdbb162d1511bd78a912aed0f2637af65572ae INLINECALLDICT + TRUE + RETALT + }> + }>ELSE<{ + 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 + $MyContract$_contract_load INLINECALLDICT + -ROT + $MyContract$_contract_router_internal INLINECALLDICT + 130 THROWIFNOT + $MyContract$_contract_store INLINECALLDICT + }> +}END>c diff --git a/src/test/features/output/implicit-init_MyContract.code.rev.fif b/src/test/features/output/implicit-init_MyContract.code.rev.fif new file mode 100644 index 000000000..a8cfbdc5e --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.code.rev.fif @@ -0,0 +1,347 @@ +PROGRAM{ + DECLPROC recv_internal; + DECLPROC ?fun_103307; + DECLPROC supported_interfaces; + DECLPROC lazy_deployment_completed; + DECLPROC get_abi_ipfs; + DECLPROC ?fun_ref_36266a5855831da9; + DECLPROC ?fun_ref_40d98146a47dbe3b; + DECLPROC ?fun_ref_644ef5250652bdfa; + DECLPROC ?fun_ref_b93b9862cda1783c; + DECLPROC ?fun_ref_df5396d9c1e677c7; + DECLPROC ?fun_ref_e31d986f279fa0fb; + recv_internal PROC:<{ + s0 s1 XCHG + CTOS + 4 LDU + s0 s1 XCHG + 1 PUSHINT + AND + -1 MULCONST + s0 s1 XCHG + LDMSGADDR + s0 s1 XCHG + s0 PUSH + SBITS + 267 PUSHINT + EQUAL + 136 THROWIFNOT + s0 PUSH + 11 PLDU + s0 PUSH + 1279 PUSHINT + EQUAL + 137 THROWIF + 10 PUSHPOW2 + EQUAL + 136 THROWIFNOT + s0 s6 s4 PUXCPU + s0 s3 XCHG + 4 TUPLE + 1 SETGLOBVAR + s0 s2 XCHG + 2 SETGLOBVAR + ?fun_ref_36266a5855831da9 INLINECALLDICT + ROTREV + ?fun_ref_df5396d9c1e677c7 INLINECALLDICT + 130 THROWIFNOT + NEWC + 3 GETGLOBVAR + s0 s1 XCHG + STREF + -1 PUSHINT + s0 s1 XCHG + 1 STI + s0 s1 XCHG + s0 s1 XCHG + 257 PUSHINT + STIX + ENDC + c4 POP + }> + ?fun_103307 PROC:<{ + ?fun_ref_36266a5855831da9 INLINECALLDICT + ?fun_ref_40d98146a47dbe3b INLINECALLDICT + s1 POP + }> + supported_interfaces PROC:<{ + 123515602279859691144772641439386770278 PUSHINT + 209801025412363888721030803524359905849 PUSHINT + 42980537499636128163026532310500881091 PUSHINT + 36993126140238121407019133875791708966 PUSHINT + 209474421377847335869795010607481022628 PUSHINT + }> + lazy_deployment_completed PROC:<{ + c4 PUSH + CTOS + 1 LDI + s0 s1 XCHG + }> + get_abi_ipfs PROC:<{ + x{697066733A2F2F516D554D4E70757564633667354C584C5975315471464858556B7837725174755550704C6A657877434B4836523982_} PUSHSLICE + }> + ?fun_ref_36266a5855831da9 PROCREF:<{ + c4 PUSH + CTOS + LDREF + s0 s1 XCHG + 3 SETGLOBVAR + 1 LDI + s0 s1 XCHG + <{ + 257 PUSHINT + LDIX + s0 s1 XCHG + s1 POP + }> PUSHCONT + IFJMP + s0 POP + MYADDR + 11 PLDU + 10 PUSHPOW2 + EQUAL + 137 THROWIFNOT + ?fun_ref_644ef5250652bdfa INLINECALLDICT + }> + ?fun_ref_40d98146a47dbe3b PROCREF:<{ + s0 PUSH + }> + ?fun_ref_644ef5250652bdfa PROCREF:<{ + 0 PUSHINT + }> + ?fun_ref_b93b9862cda1783c PROCREF:<{ + NEWC + 1 PUSHINT + s0 s1 XCHG + 2 STI + s0 s7 XCHG2 + s0 s1 XCHG + 1 STI + 0 PUSHINT + s0 s1 XCHG + 3 STI + s0 s5 XCHG2 + s0 PUSH + SBITS + 267 PUSHINT + EQUAL + 136 THROWIFNOT + s0 PUSH + 11 PLDU + s0 PUSH + 1279 PUSHINT + EQUAL + 137 THROWIF + 10 PUSHPOW2 + EQUAL + 136 THROWIFNOT + STSLICER + s0 s3 XCHG2 + STGRAMS + 0 PUSHINT + s0 s1 XCHG + 105 STI + s3 PUSH + ISNULL + NOT + <{ + -1 PUSHINT + }> PUSHCONT + <{ + s4 PUSH + ISNULL + NOT + }> PUSHCONT + IFELSE + <{ + s3 POP + s3 POP + s0 s1 XCHG + 0 PUSHINT + s0 s1 XCHG + 1 STI + }> PUSHCONT + <{ + -1 PUSHINT + s0 s1 XCHG + 1 STI + NEWC + 0 PUSHINT + s0 s1 XCHG + 1 STI + 0 PUSHINT + s0 s1 XCHG + 1 STI + s4 PUSH + ISNULL + NOT + <{ + -1 PUSHINT + s0 s1 XCHG + 1 STI + s0 s4 XCHG + s0 PUSH + ISNULL + 128 THROWIF + s0 s4 XCHG2 + STREF + }> PUSHCONT + <{ + s4 POP + s0 s3 XCHG + 0 PUSHINT + s0 s1 XCHG + 1 STI + }> PUSHCONT + IFELSE + s4 PUSH + ISNULL + NOT + <{ + -1 PUSHINT + s0 s1 XCHG + 1 STI + s0 s4 XCHG + s0 PUSH + ISNULL + 128 THROWIF + s0 s4 XCHG2 + STREF + }> PUSHCONT + <{ + s4 POP + s0 s3 XCHG + 0 PUSHINT + s0 s1 XCHG + 1 STI + }> PUSHCONT + IFELSE + 0 PUSHINT + s0 s1 XCHG + 1 STI + s0 s2 XCHG + -1 PUSHINT + s0 s1 XCHG + 1 STI + s0 s2 XCHG + ENDC + ROT + STREF + }> IFREFELSE + s1 PUSH + ISNULL + NOT + <{ + -1 PUSHINT + s0 s1 XCHG + 1 STI + s0 s1 XCHG + s0 PUSH + ISNULL + 128 THROWIF + s0 s1 XCHG + STREF + }> PUSHCONT + <{ + s1 POP + 0 PUSHINT + s0 s1 XCHG + 1 STI + }> PUSHCONT + IFELSE + ENDC + s0 s1 XCHG + SENDRAWMSG + }> + ?fun_ref_df5396d9c1e677c7 PROCREF:<{ + 2 SAVE + SAMEALTSAVE + s0 s1 XCHG + <{ + s0 POP + -1 PUSHINT + }> PUSHCONT + IFJMP + 0 PUSHINT + s1 PUSH + SBITS + 31 GTINT + <{ + s0 POP + s0 PUSH + 32 PLDU + }> PUSHCONT + IF + s0 PUSH + 2490013878 PUSHINT + EQUAL + <{ + s0 POP + 32 LDU + s0 s1 XCHG + 2490013878 PUSHINT + EQUAL + 129 THROWIFNOT + 64 LDU + s0 s1 XCHG + s1 POP + NEWC + s0 s1 XCHG + 2952335191 PUSHINT + ROT + 32 STU + 64 STU + ENDC + 2 GETGLOBVAR + s0 s1 XCHG + 0 PUSHINT + NULL + ?fun_ref_e31d986f279fa0fb INLINECALLDICT + -1 PUSHINT + }> PUSHCONT + IFJMP + 0 EQINT + <{ + HASHSU + 89092981215441470209245890604563109773385607357076622359718516871332286001838 PUSHINT + EQUAL + <{ + INC + -1 PUSHINT + RETFALSE + }> PUSHCONT + IFJMP + }> PUSHCONT + <{ + s0 POP + }> PUSHCONT + IFELSE + 0 PUSHINT + }> + ?fun_ref_e31d986f279fa0fb PROCREF:<{ + NULL + NULL + s2 PUSH + ISNULL + NOT + <{ + DROP2 + s0 PUSH + ISNULL + 128 THROWIF + 2 UNTUPLE + s0 s1 XCHG + }> PUSHCONT + <{ + s2 POP + }> PUSHCONT + IFELSE + s2 s4 XCHG + 0 PUSHINT + s0 s3 XCHG + s0 s4 XCHG + 66 PUSHINT + s2 s3 XCHG2 + ?fun_ref_b93b9862cda1783c INLINECALLDICT + }> +}END>c \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.headers.fc b/src/test/features/output/implicit-init_MyContract.headers.fc new file mode 100644 index 000000000..091a7cfd0 --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.headers.fc @@ -0,0 +1,70 @@ +;; +;; Header files for MyContract +;; NOTE: declarations are sorted for optimal order +;; + +;; __tact_verify_address +slice __tact_verify_address(slice address) inline; + +;; __tact_store_address +builder __tact_store_address(builder b, slice address) inline; + +;; __tact_my_balance +int __tact_my_balance() inline; + +;; __tact_not_null +forall X -> X __tact_not_null(X x) inline; + +;; __tact_context_get +(int, slice, int, slice) __tact_context_get() inline; + +;; __tact_context_get_sender +slice __tact_context_get_sender() inline; + +;; __tact_store_bool +builder __tact_store_bool(builder b, int v) inline; + +;; $Deploy$_load +(slice, ((int))) $Deploy$_load(slice sc_0) inline; + +;; $DeployOk$_store +builder $DeployOk$_store(builder build_0, (int) v) inline; + +;; $DeployOk$_store_cell +cell $DeployOk$_store_cell((int) v) inline; + +;; $MyContract$_store +builder $MyContract$_store(builder build_0, (int) v) inline; + +;; $MyContract$_load +(slice, ((int))) $MyContract$_load(slice sc_0) inline; + +;; $StateInit$_not_null +((cell, cell)) $StateInit$_not_null(tuple v) inline; + +;; $MyContract$_contract_init +(int) $MyContract$_contract_init() impure inline_ref; + +;; $MyContract$_contract_load +(int) $MyContract$_contract_load() impure inline_ref; + +;; $MyContract$_contract_store +() $MyContract$_contract_store((int) v) impure inline; + +;; $global_send +() $global_send((int, slice, int, int, cell, cell, cell) $params) impure inline_ref; + +;; $MyContract$_fun_getCounter +((int), int) $MyContract$_fun_getCounter((int) $self) impure inline_ref; + +;; $SendParameters$_constructor_bounce_to_value_mode_body_code_data +((int, slice, int, int, cell, cell, cell)) $SendParameters$_constructor_bounce_to_value_mode_body_code_data(int bounce, slice to, int value, int mode, cell body, cell code, cell data) inline; + +;; $MyContract$_fun_forward +((int), ()) $MyContract$_fun_forward((int) $self, slice $to, cell $body, int $bounce, tuple $init) impure inline_ref; + +;; $MyContract$_fun_notify +((int), ()) $MyContract$_fun_notify((int) $self, cell $body) impure inline; + +;; $DeployOk$_constructor_queryId +((int)) $DeployOk$_constructor_queryId(int queryId) inline; diff --git a/src/test/features/output/implicit-init_MyContract.md b/src/test/features/output/implicit-init_MyContract.md new file mode 100644 index 000000000..eabf84b3e --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.md @@ -0,0 +1,61 @@ +# TACT Compilation Report +Contract: MyContract +BOC Size: 690 bytes + +# Types +Total Types: 6 + +## StateInit +TLB: `_ code:^cell data:^cell = StateInit` +Signature: `StateInit{code:^cell,data:^cell}` + +## Context +TLB: `_ bounced:bool sender:address value:int257 raw:^slice = Context` +Signature: `Context{bounced:bool,sender:address,value:int257,raw:^slice}` + +## SendParameters +TLB: `_ bounce:bool to:address value:int257 mode:int257 body:Maybe ^cell code:Maybe ^cell data:Maybe ^cell = SendParameters` +Signature: `SendParameters{bounce:bool,to:address,value:int257,mode:int257,body:Maybe ^cell,code:Maybe ^cell,data:Maybe ^cell}` + +## Deploy +TLB: `deploy#946a98b6 queryId:uint64 = Deploy` +Signature: `Deploy{queryId:uint64}` + +## DeployOk +TLB: `deploy_ok#aff90f57 queryId:uint64 = DeployOk` +Signature: `DeployOk{queryId:uint64}` + +## FactoryDeploy +TLB: `factory_deploy#6d0ff13b queryId:uint64 cashback:address = FactoryDeploy` +Signature: `FactoryDeploy{queryId:uint64,cashback:address}` + +# Get Methods +Total Get Methods: 1 + +## getCounter + +# Error Codes +2: Stack undeflow +3: Stack overflow +4: Integer overflow +5: Integer out of expected range +6: Invalid opcode +7: Type check error +8: Cell overflow +9: Cell underflow +10: Dictionary error +13: Out of gas error +32: Method ID not found +34: Action is invalid or not supported +37: Not enough TON +38: Not enough extra-currencies +128: Null reference exception +129: Invalid serialization prefix +130: Invalid incoming message +131: Constraints error +132: Access denied +133: Contract stopped +134: Invalid argument +135: Code of a contract was not found +136: Invalid address +137: Masterchain support is not enabled for this contract \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.pkg b/src/test/features/output/implicit-init_MyContract.pkg new file mode 100644 index 000000000..c5e04db45 --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.pkg @@ -0,0 +1 @@ +{"name":"MyContract","code":"te6ccgECEQEAAqYAART/APSkE/S88sgLAQIBYgIDAp7QAdDTAwFxsKMB+kABINdJgQELuvLgiCDXCwoggQT/uvLQiYMJuvLgiFRQUwNvBPhhAvhi2zxZ2zzy4ILI+EMBzH8BygABAYEBAc8Aye1UDAQCAVgICQL27aLt+wGSMH/gcCHXScIflTAg1wsf3iCCEJRqmLa6jqgw0x8BghCUapi2uvLggdM/ATHIAYIQr/kPV1jLH8s/yfhCAXBt2zx/4MAAjiv5AYLwxPjXIxLt/e9be+x4M727Fi0VEb14qRKu0PJjevZVcq66lKR/2zHgkTDiBQ4BOm1tIm6zmVsgbvLQgG8iAZEy4hAkcAMEgEJQI9s8BgHKyHEBygFQBwHKAHABygJQBSDXSYEBC7ry4Igg1wsKIIEE/7ry0ImDCbry4IjPFlAD+gJwAcpoI26zkX+TJG6z4pczMwFwAcoA4w0hbrOcfwHKAAEgbvLQgAHMlTFwAcoA4skB+wAHAJh/AcoAyHABygBwAcoAJG6znX8BygAEIG7y0IBQBMyWNANwAcoA4iRus51/AcoABCBu8tCAUATMljQDcAHKAOJwAcoAAn8BygACyVjMAgEgCgsCAUgPEAIPtnF7Z5tnhjAMDQC5t3owTgudh6ullc9j0J2HOslQo2zQThO6xqWlbI+WZFp15b++LEcwTgQKuANwDOxymcsHVcjktlhwTgN6k73yqLLeOOp6e8CrOGTQThOy6ctWadluZ0HSzbKM3RSQAULtRNDUAfhj0gABl4EBAdcAATHgMPgo1wsKgwm68uCJ2zwOAAIgAAJwABGwr7tRNDSAAGAAdbJu40NWlwZnM6Ly9RbVVNTnB1dWRjNmc1TFhMWXUxVHFGSFhVa3g3clF0dVVQcExqZXh3Q0tINlI5gg","abi":"{\"name\":\"MyContract\",\"types\":[{\"name\":\"StateInit\",\"header\":null,\"fields\":[{\"name\":\"code\",\"type\":{\"kind\":\"simple\",\"type\":\"cell\",\"optional\":false}},{\"name\":\"data\",\"type\":{\"kind\":\"simple\",\"type\":\"cell\",\"optional\":false}}]},{\"name\":\"Context\",\"header\":null,\"fields\":[{\"name\":\"bounced\",\"type\":{\"kind\":\"simple\",\"type\":\"bool\",\"optional\":false}},{\"name\":\"sender\",\"type\":{\"kind\":\"simple\",\"type\":\"address\",\"optional\":false}},{\"name\":\"value\",\"type\":{\"kind\":\"simple\",\"type\":\"int\",\"optional\":false,\"format\":257}},{\"name\":\"raw\",\"type\":{\"kind\":\"simple\",\"type\":\"slice\",\"optional\":false}}]},{\"name\":\"SendParameters\",\"header\":null,\"fields\":[{\"name\":\"bounce\",\"type\":{\"kind\":\"simple\",\"type\":\"bool\",\"optional\":false}},{\"name\":\"to\",\"type\":{\"kind\":\"simple\",\"type\":\"address\",\"optional\":false}},{\"name\":\"value\",\"type\":{\"kind\":\"simple\",\"type\":\"int\",\"optional\":false,\"format\":257}},{\"name\":\"mode\",\"type\":{\"kind\":\"simple\",\"type\":\"int\",\"optional\":false,\"format\":257}},{\"name\":\"body\",\"type\":{\"kind\":\"simple\",\"type\":\"cell\",\"optional\":true}},{\"name\":\"code\",\"type\":{\"kind\":\"simple\",\"type\":\"cell\",\"optional\":true}},{\"name\":\"data\",\"type\":{\"kind\":\"simple\",\"type\":\"cell\",\"optional\":true}}]},{\"name\":\"Deploy\",\"header\":2490013878,\"fields\":[{\"name\":\"queryId\",\"type\":{\"kind\":\"simple\",\"type\":\"uint\",\"optional\":false,\"format\":64}}]},{\"name\":\"DeployOk\",\"header\":2952335191,\"fields\":[{\"name\":\"queryId\",\"type\":{\"kind\":\"simple\",\"type\":\"uint\",\"optional\":false,\"format\":64}}]},{\"name\":\"FactoryDeploy\",\"header\":1829761339,\"fields\":[{\"name\":\"queryId\",\"type\":{\"kind\":\"simple\",\"type\":\"uint\",\"optional\":false,\"format\":64}},{\"name\":\"cashback\",\"type\":{\"kind\":\"simple\",\"type\":\"address\",\"optional\":false}}]}],\"receivers\":[{\"receiver\":\"internal\",\"message\":{\"kind\":\"text\",\"text\":\"increment\"}},{\"receiver\":\"internal\",\"message\":{\"kind\":\"typed\",\"type\":\"Deploy\"}}],\"getters\":[{\"name\":\"getCounter\",\"arguments\":[],\"returnType\":{\"kind\":\"simple\",\"type\":\"int\",\"optional\":false,\"format\":257}}],\"errors\":{\"2\":{\"message\":\"Stack undeflow\"},\"3\":{\"message\":\"Stack overflow\"},\"4\":{\"message\":\"Integer overflow\"},\"5\":{\"message\":\"Integer out of expected range\"},\"6\":{\"message\":\"Invalid opcode\"},\"7\":{\"message\":\"Type check error\"},\"8\":{\"message\":\"Cell overflow\"},\"9\":{\"message\":\"Cell underflow\"},\"10\":{\"message\":\"Dictionary error\"},\"13\":{\"message\":\"Out of gas error\"},\"32\":{\"message\":\"Method ID not found\"},\"34\":{\"message\":\"Action is invalid or not supported\"},\"37\":{\"message\":\"Not enough TON\"},\"38\":{\"message\":\"Not enough extra-currencies\"},\"128\":{\"message\":\"Null reference exception\"},\"129\":{\"message\":\"Invalid serialization prefix\"},\"130\":{\"message\":\"Invalid incoming message\"},\"131\":{\"message\":\"Constraints error\"},\"132\":{\"message\":\"Access denied\"},\"133\":{\"message\":\"Contract stopped\"},\"134\":{\"message\":\"Invalid argument\"},\"135\":{\"message\":\"Code of a contract was not found\"},\"136\":{\"message\":\"Invalid address\"},\"137\":{\"message\":\"Masterchain support is not enabled for this contract\"}},\"interfaces\":[\"org.ton.introspection.v0\",\"org.ton.abi.ipfs.v0\",\"org.ton.deploy.lazy.v0\",\"org.ton.debug.v0\",\"org.ton.chain.workchain.v0\"]}","init":{"kind":"direct","args":[],"prefix":{"bits":1,"value":0},"deployment":{"kind":"system-cell","system":"te6cckECEwEAArAAAQHAAQEFoXjPAgEU/wD0pBP0vPLICwMCAWIMBAIBWAgFAgFIBwYAdbJu40NWlwZnM6Ly9RbVVNTnB1dWRjNmc1TFhMWXUxVHFGSFhVa3g3clF0dVVQcExqZXh3Q0tINlI5ggABGwr7tRNDSAAGACASAKCQC5t3owTgudh6ullc9j0J2HOslQo2zQThO6xqWlbI+WZFp15b++LEcwTgQKuANwDOxymcsHVcjktlhwTgN6k73yqLLeOOp6e8CrOGTQThOy6ctWadluZ0HSzbKM3RSQAg+2cXtnm2eGMBELAAIgAp7QAdDTAwFxsKMB+kABINdJgQELuvLgiCDXCwoggQT/uvLQiYMJuvLgiFRQUwNvBPhhAvhi2zxZ2zzy4ILI+EMBzH8BygABAYEBAc8Aye1UEQ0C9u2i7fsBkjB/4HAh10nCH5UwINcLH94gghCUapi2uo6oMNMfAYIQlGqYtrry4IHTPwExyAGCEK/5D1dYyx/LP8n4QgFwbds8f+DAAI4r+QGC8MT41yMS7f3vW3vseDO9uxYtFRG9eKkSrtDyY3r2VXKuupSkf9sx4JEw4g4SATptbSJus5lbIG7y0IBvIgGRMuIQJHADBIBCUCPbPA8ByshxAcoBUAcBygBwAcoCUAUg10mBAQu68uCIINcLCiCBBP+68tCJgwm68uCIzxZQA/oCcAHKaCNus5F/kyRus+KXMzMBcAHKAOMNIW6znH8BygABIG7y0IABzJUxcAHKAOLJAfsAEACYfwHKAMhwAcoAcAHKACRus51/AcoABCBu8tCAUATMljQDcAHKAOIkbrOdfwHKAAQgbvLQgFAEzJY0A3ABygDicAHKAAJ/AcoAAslYzAFC7UTQ1AH4Y9IAAZeBAQHXAAEx4DD4KNcLCoMJuvLgids8EgACcMdIBL0="}},"sources":{"src/test/features/implicit-init.tact":"aW1wb3J0ICJAc3RkbGliL2RlcGxveSI7Cgpjb250cmFjdCBNeUNvbnRyYWN0IHdpdGggRGVwbG95YWJsZSB7CiAgICBjb3VudGVyOiBJbnQgPSAwOwoKICAgIHJlY2VpdmUoImluY3JlbWVudCIpIHsKICAgICAgICBzZWxmLmNvdW50ZXIgKz0gMTsKICAgIH0KCiAgICBnZXQgZnVuIGdldENvdW50ZXIoKTogSW50IHsKICAgICAgICByZXR1cm4gc2VsZi5jb3VudGVyOwogICAgfQp9"},"compiler":{"name":"tact","version":"invalid","parameters":"{\"entrypoint\":\"./src/test/features/implicit-init.tact\",\"options\":{\"debug\":true}}"}} \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.stdlib.fc b/src/test/features/output/implicit-init_MyContract.stdlib.fc new file mode 100644 index 000000000..7c9b553f0 --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.stdlib.fc @@ -0,0 +1,111 @@ +global (int, slice, int, slice) __tact_context; +global slice __tact_context_sender; +global cell __tact_context_sys; +global int __tact_randomized; + +slice __tact_verify_address(slice address) inline { + throw_unless(136, address.slice_bits() == 267); + var h = address.preload_uint(11); + throw_if(137, h == 1279); + throw_unless(136, h == 1024); + return address; +} + +builder __tact_store_address(builder b, slice address) inline { + return b.store_slice(__tact_verify_address(address)); +} + +int __tact_my_balance() inline { + return pair_first(get_balance()); +} + +forall X -> X __tact_not_null(X x) inline { + throw_if(128, null?(x)); return x; +} + +(int, slice, int, slice) __tact_context_get() inline { + return __tact_context; +} + +slice __tact_context_get_sender() inline { + return __tact_context_sender; +} + +builder __tact_store_bool(builder b, int v) inline { + return b.store_int(v, 1); +} + +forall X0, X1 -> (X0, X1) __tact_tuple_destroy_2(tuple v) asm "2 UNTUPLE"; + +() $global_send((int, slice, int, int, cell, cell, cell) $params) impure inline_ref { + var (($params'bounce, $params'to, $params'value, $params'mode, $params'body, $params'code, $params'data)) = $params; + builder $b = begin_cell(); + $b = store_int($b, 1, 2); + $b = __tact_store_bool($b, $params'bounce); + $b = store_int($b, 0, 3); + $b = __tact_store_address($b, $params'to); + $b = store_coins($b, $params'value); + $b = store_int($b, 0, ((((1 + 4) + 4) + 64) + 32)); + if (( ((~ null?($params'code))) ? (true) : ((~ null?($params'data))) )) { + $b = __tact_store_bool($b, true); + builder $bc = begin_cell(); + $bc = __tact_store_bool($bc, false); + $bc = __tact_store_bool($bc, false); + if ((~ null?($params'code))) { + $bc = __tact_store_bool($bc, true); + $bc = store_ref($bc, __tact_not_null($params'code)); + } else { + $bc = __tact_store_bool($bc, false); + } + if ((~ null?($params'data))) { + $bc = __tact_store_bool($bc, true); + $bc = store_ref($bc, __tact_not_null($params'data)); + } else { + $bc = __tact_store_bool($bc, false); + } + $bc = __tact_store_bool($bc, false); + $b = __tact_store_bool($b, true); + $b = store_ref($b, end_cell($bc)); + } else { + $b = __tact_store_bool($b, false); + } + cell $body = $params'body; + if ((~ null?($body))) { + $b = __tact_store_bool($b, true); + $b = store_ref($b, __tact_not_null($body)); + } else { + $b = __tact_store_bool($b, false); + } + cell $c = end_cell($b); + send_raw_message($c, $params'mode); +} + +((int), ()) $MyContract$_fun_forward((int) $self, slice $to, cell $body, int $bounce, tuple $init) impure inline_ref { + var (($self'counter)) = $self; + var ($init) = $init; + cell $code = null(); + cell $data = null(); + if ((~ null?($init))) { + var ($init2'code, $init2'data) = $StateInit$_not_null($init); + $code = $init2'code; + $data = $init2'data; + } + if ((0 > 0)) { + var ($ctx'bounced, $ctx'sender, $ctx'value, $ctx'raw) = __tact_context_get(); + int $balance = __tact_my_balance(); + int $balanceBeforeMessage = ($balance - $ctx'value); + if (($balanceBeforeMessage < 0)) { + raw_reserve(0, 0); + $global_send($SendParameters$_constructor_bounce_to_value_mode_body_code_data($bounce, $to, 0, (128 + 2), $body, $code, $data)); + return (($self'counter), ()); + } + } + $global_send($SendParameters$_constructor_bounce_to_value_mode_body_code_data($bounce, $to, 0, (64 + 2), $body, $code, $data)); + return (($self'counter), ()); +} + +((int), ()) $MyContract$_fun_notify((int) $self, cell $body) impure inline { + var (($self'counter)) = $self; + ($self'counter)~$MyContract$_fun_forward(__tact_context_get_sender(), $body, false, null()); + return (($self'counter), ()); +} \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.storage.fc b/src/test/features/output/implicit-init_MyContract.storage.fc new file mode 100644 index 000000000..7d7aa8e99 --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.storage.fc @@ -0,0 +1,88 @@ +;; +;; Type: StateInit +;; TLB: _ code:^cell data:^cell = StateInit +;; + +((cell, cell)) $StateInit$_not_null(tuple v) inline { + throw_if(128, null?(v)); + var (cell vvv'code, cell vvv'data) = __tact_tuple_destroy_2(v); + return (vvv'code, vvv'data); +} + +;; +;; Type: SendParameters +;; TLB: _ bounce:bool to:address value:int257 mode:int257 body:Maybe ^cell code:Maybe ^cell data:Maybe ^cell = SendParameters +;; + +((int, slice, int, int, cell, cell, cell)) $SendParameters$_constructor_bounce_to_value_mode_body_code_data(int bounce, slice to, int value, int mode, cell body, cell code, cell data) inline { + return (bounce, to, value, mode, body, code, data); +} + +;; +;; Type: Deploy +;; Header: 0x946a98b6 +;; TLB: deploy#946a98b6 queryId:uint64 = Deploy +;; + +(slice, ((int))) $Deploy$_load(slice sc_0) inline { + throw_unless(129, sc_0~load_uint(32) == 2490013878); + var v'queryId = sc_0~load_uint(64); + return (sc_0, (v'queryId)); +} + +;; +;; Type: DeployOk +;; Header: 0xaff90f57 +;; TLB: deploy_ok#aff90f57 queryId:uint64 = DeployOk +;; + +builder $DeployOk$_store(builder build_0, (int) v) inline { + var (v'queryId) = v; + build_0 = store_uint(build_0, 2952335191, 32); + build_0 = build_0.store_uint(v'queryId, 64); + return build_0; +} + +cell $DeployOk$_store_cell((int) v) inline { + return $DeployOk$_store(begin_cell(), v).end_cell(); +} + +((int)) $DeployOk$_constructor_queryId(int queryId) inline { + return (queryId); +} + +;; +;; Type: MyContract +;; + +builder $MyContract$_store(builder build_0, (int) v) inline { + var (v'counter) = v; + build_0 = build_0.store_int(v'counter, 257); + return build_0; +} + +(slice, ((int))) $MyContract$_load(slice sc_0) inline { + var v'counter = sc_0~load_int(257); + return (sc_0, (v'counter)); +} + +(int) $MyContract$_contract_load() impure inline_ref { + slice $sc = get_data().begin_parse(); + __tact_context_sys = $sc~load_ref(); + int $loaded = $sc~load_int(1); + if ($loaded) { + return $sc~$MyContract$_load(); + } else { + ;; Allow only workchain deployments + throw_unless(137, my_address().preload_uint(11) == 1024); + return $MyContract$_contract_init(); + } +} + +() $MyContract$_contract_store((int) v) impure inline { + builder b = begin_cell(); + b = b.store_ref(__tact_context_sys); + b = b.store_int(true, 1); + b = $MyContract$_store(b, v); + set_data(b.end_cell()); +} \ No newline at end of file diff --git a/src/test/features/output/implicit-init_MyContract.ts b/src/test/features/output/implicit-init_MyContract.ts new file mode 100644 index 000000000..a5aec01f8 --- /dev/null +++ b/src/test/features/output/implicit-init_MyContract.ts @@ -0,0 +1,442 @@ +import { + Cell, + Slice, + Address, + Builder, + beginCell, + ComputeError, + TupleItem, + TupleReader, + Dictionary, + contractAddress, + ContractProvider, + Sender, + Contract, + ContractABI, + ABIType, + ABIGetter, + ABIReceiver, + TupleBuilder, + DictionaryValue +} from '@ton/core'; + +export type StateInit = { + $$type: 'StateInit'; + code: Cell; + data: Cell; +} + +export function storeStateInit(src: StateInit) { + return (builder: Builder) => { + let b_0 = builder; + b_0.storeRef(src.code); + b_0.storeRef(src.data); + }; +} + +export function loadStateInit(slice: Slice) { + let sc_0 = slice; + let _code = sc_0.loadRef(); + let _data = sc_0.loadRef(); + return { $$type: 'StateInit' as const, code: _code, data: _data }; +} + +function loadTupleStateInit(source: TupleReader) { + let _code = source.readCell(); + let _data = source.readCell(); + return { $$type: 'StateInit' as const, code: _code, data: _data }; +} + +function storeTupleStateInit(source: StateInit) { + let builder = new TupleBuilder(); + builder.writeCell(source.code); + builder.writeCell(source.data); + return builder.build(); +} + +function dictValueParserStateInit(): DictionaryValue { + return { + serialize: (src, buidler) => { + buidler.storeRef(beginCell().store(storeStateInit(src)).endCell()); + }, + parse: (src) => { + return loadStateInit(src.loadRef().beginParse()); + } + } +} + +export type Context = { + $$type: 'Context'; + bounced: boolean; + sender: Address; + value: bigint; + raw: Cell; +} + +export function storeContext(src: Context) { + return (builder: Builder) => { + let b_0 = builder; + b_0.storeBit(src.bounced); + b_0.storeAddress(src.sender); + b_0.storeInt(src.value, 257); + b_0.storeRef(src.raw); + }; +} + +export function loadContext(slice: Slice) { + let sc_0 = slice; + let _bounced = sc_0.loadBit(); + let _sender = sc_0.loadAddress(); + let _value = sc_0.loadIntBig(257); + let _raw = sc_0.loadRef(); + return { $$type: 'Context' as const, bounced: _bounced, sender: _sender, value: _value, raw: _raw }; +} + +function loadTupleContext(source: TupleReader) { + let _bounced = source.readBoolean(); + let _sender = source.readAddress(); + let _value = source.readBigNumber(); + let _raw = source.readCell(); + return { $$type: 'Context' as const, bounced: _bounced, sender: _sender, value: _value, raw: _raw }; +} + +function storeTupleContext(source: Context) { + let builder = new TupleBuilder(); + builder.writeBoolean(source.bounced); + builder.writeAddress(source.sender); + builder.writeNumber(source.value); + builder.writeSlice(source.raw); + return builder.build(); +} + +function dictValueParserContext(): DictionaryValue { + return { + serialize: (src, buidler) => { + buidler.storeRef(beginCell().store(storeContext(src)).endCell()); + }, + parse: (src) => { + return loadContext(src.loadRef().beginParse()); + } + } +} + +export type SendParameters = { + $$type: 'SendParameters'; + bounce: boolean; + to: Address; + value: bigint; + mode: bigint; + body: Cell | null; + code: Cell | null; + data: Cell | null; +} + +export function storeSendParameters(src: SendParameters) { + return (builder: Builder) => { + let b_0 = builder; + b_0.storeBit(src.bounce); + b_0.storeAddress(src.to); + b_0.storeInt(src.value, 257); + b_0.storeInt(src.mode, 257); + if (src.body !== null && src.body !== undefined) { b_0.storeBit(true).storeRef(src.body); } else { b_0.storeBit(false); } + if (src.code !== null && src.code !== undefined) { b_0.storeBit(true).storeRef(src.code); } else { b_0.storeBit(false); } + if (src.data !== null && src.data !== undefined) { b_0.storeBit(true).storeRef(src.data); } else { b_0.storeBit(false); } + }; +} + +export function loadSendParameters(slice: Slice) { + let sc_0 = slice; + let _bounce = sc_0.loadBit(); + let _to = sc_0.loadAddress(); + let _value = sc_0.loadIntBig(257); + let _mode = sc_0.loadIntBig(257); + let _body = sc_0.loadBit() ? sc_0.loadRef() : null; + let _code = sc_0.loadBit() ? sc_0.loadRef() : null; + let _data = sc_0.loadBit() ? sc_0.loadRef() : null; + return { $$type: 'SendParameters' as const, bounce: _bounce, to: _to, value: _value, mode: _mode, body: _body, code: _code, data: _data }; +} + +function loadTupleSendParameters(source: TupleReader) { + let _bounce = source.readBoolean(); + let _to = source.readAddress(); + let _value = source.readBigNumber(); + let _mode = source.readBigNumber(); + let _body = source.readCellOpt(); + let _code = source.readCellOpt(); + let _data = source.readCellOpt(); + return { $$type: 'SendParameters' as const, bounce: _bounce, to: _to, value: _value, mode: _mode, body: _body, code: _code, data: _data }; +} + +function storeTupleSendParameters(source: SendParameters) { + let builder = new TupleBuilder(); + builder.writeBoolean(source.bounce); + builder.writeAddress(source.to); + builder.writeNumber(source.value); + builder.writeNumber(source.mode); + builder.writeCell(source.body); + builder.writeCell(source.code); + builder.writeCell(source.data); + return builder.build(); +} + +function dictValueParserSendParameters(): DictionaryValue { + return { + serialize: (src, buidler) => { + buidler.storeRef(beginCell().store(storeSendParameters(src)).endCell()); + }, + parse: (src) => { + return loadSendParameters(src.loadRef().beginParse()); + } + } +} + +export type Deploy = { + $$type: 'Deploy'; + queryId: bigint; +} + +export function storeDeploy(src: Deploy) { + return (builder: Builder) => { + let b_0 = builder; + b_0.storeUint(2490013878, 32); + b_0.storeUint(src.queryId, 64); + }; +} + +export function loadDeploy(slice: Slice) { + let sc_0 = slice; + if (sc_0.loadUint(32) !== 2490013878) { throw Error('Invalid prefix'); } + let _queryId = sc_0.loadUintBig(64); + return { $$type: 'Deploy' as const, queryId: _queryId }; +} + +function loadTupleDeploy(source: TupleReader) { + let _queryId = source.readBigNumber(); + return { $$type: 'Deploy' as const, queryId: _queryId }; +} + +function storeTupleDeploy(source: Deploy) { + let builder = new TupleBuilder(); + builder.writeNumber(source.queryId); + return builder.build(); +} + +function dictValueParserDeploy(): DictionaryValue { + return { + serialize: (src, buidler) => { + buidler.storeRef(beginCell().store(storeDeploy(src)).endCell()); + }, + parse: (src) => { + return loadDeploy(src.loadRef().beginParse()); + } + } +} + +export type DeployOk = { + $$type: 'DeployOk'; + queryId: bigint; +} + +export function storeDeployOk(src: DeployOk) { + return (builder: Builder) => { + let b_0 = builder; + b_0.storeUint(2952335191, 32); + b_0.storeUint(src.queryId, 64); + }; +} + +export function loadDeployOk(slice: Slice) { + let sc_0 = slice; + if (sc_0.loadUint(32) !== 2952335191) { throw Error('Invalid prefix'); } + let _queryId = sc_0.loadUintBig(64); + return { $$type: 'DeployOk' as const, queryId: _queryId }; +} + +function loadTupleDeployOk(source: TupleReader) { + let _queryId = source.readBigNumber(); + return { $$type: 'DeployOk' as const, queryId: _queryId }; +} + +function storeTupleDeployOk(source: DeployOk) { + let builder = new TupleBuilder(); + builder.writeNumber(source.queryId); + return builder.build(); +} + +function dictValueParserDeployOk(): DictionaryValue { + return { + serialize: (src, buidler) => { + buidler.storeRef(beginCell().store(storeDeployOk(src)).endCell()); + }, + parse: (src) => { + return loadDeployOk(src.loadRef().beginParse()); + } + } +} + +export type FactoryDeploy = { + $$type: 'FactoryDeploy'; + queryId: bigint; + cashback: Address; +} + +export function storeFactoryDeploy(src: FactoryDeploy) { + return (builder: Builder) => { + let b_0 = builder; + b_0.storeUint(1829761339, 32); + b_0.storeUint(src.queryId, 64); + b_0.storeAddress(src.cashback); + }; +} + +export function loadFactoryDeploy(slice: Slice) { + let sc_0 = slice; + if (sc_0.loadUint(32) !== 1829761339) { throw Error('Invalid prefix'); } + let _queryId = sc_0.loadUintBig(64); + let _cashback = sc_0.loadAddress(); + return { $$type: 'FactoryDeploy' as const, queryId: _queryId, cashback: _cashback }; +} + +function loadTupleFactoryDeploy(source: TupleReader) { + let _queryId = source.readBigNumber(); + let _cashback = source.readAddress(); + return { $$type: 'FactoryDeploy' as const, queryId: _queryId, cashback: _cashback }; +} + +function storeTupleFactoryDeploy(source: FactoryDeploy) { + let builder = new TupleBuilder(); + builder.writeNumber(source.queryId); + builder.writeAddress(source.cashback); + return builder.build(); +} + +function dictValueParserFactoryDeploy(): DictionaryValue { + return { + serialize: (src, buidler) => { + buidler.storeRef(beginCell().store(storeFactoryDeploy(src)).endCell()); + }, + parse: (src) => { + return loadFactoryDeploy(src.loadRef().beginParse()); + } + } +} + + type MyContract_init_args = { + $$type: 'MyContract_init_args'; +} + +function initMyContract_init_args(src: MyContract_init_args) { + return (builder: Builder) => { + let b_0 = builder; + }; +} + +async function MyContract_init() { + const __code = Cell.fromBase64('te6ccgECEQEAAqYAART/APSkE/S88sgLAQIBYgIDAp7QAdDTAwFxsKMB+kABINdJgQELuvLgiCDXCwoggQT/uvLQiYMJuvLgiFRQUwNvBPhhAvhi2zxZ2zzy4ILI+EMBzH8BygABAYEBAc8Aye1UDAQCAVgICQL27aLt+wGSMH/gcCHXScIflTAg1wsf3iCCEJRqmLa6jqgw0x8BghCUapi2uvLggdM/ATHIAYIQr/kPV1jLH8s/yfhCAXBt2zx/4MAAjiv5AYLwxPjXIxLt/e9be+x4M727Fi0VEb14qRKu0PJjevZVcq66lKR/2zHgkTDiBQ4BOm1tIm6zmVsgbvLQgG8iAZEy4hAkcAMEgEJQI9s8BgHKyHEBygFQBwHKAHABygJQBSDXSYEBC7ry4Igg1wsKIIEE/7ry0ImDCbry4IjPFlAD+gJwAcpoI26zkX+TJG6z4pczMwFwAcoA4w0hbrOcfwHKAAEgbvLQgAHMlTFwAcoA4skB+wAHAJh/AcoAyHABygBwAcoAJG6znX8BygAEIG7y0IBQBMyWNANwAcoA4iRus51/AcoABCBu8tCAUATMljQDcAHKAOJwAcoAAn8BygACyVjMAgEgCgsCAUgPEAIPtnF7Z5tnhjAMDQC5t3owTgudh6ullc9j0J2HOslQo2zQThO6xqWlbI+WZFp15b++LEcwTgQKuANwDOxymcsHVcjktlhwTgN6k73yqLLeOOp6e8CrOGTQThOy6ctWadluZ0HSzbKM3RSQAULtRNDUAfhj0gABl4EBAdcAATHgMPgo1wsKgwm68uCJ2zwOAAIgAAJwABGwr7tRNDSAAGAAdbJu40NWlwZnM6Ly9RbVVNTnB1dWRjNmc1TFhMWXUxVHFGSFhVa3g3clF0dVVQcExqZXh3Q0tINlI5gg'); + const __system = Cell.fromBase64('te6cckECEwEAArAAAQHAAQEFoXjPAgEU/wD0pBP0vPLICwMCAWIMBAIBWAgFAgFIBwYAdbJu40NWlwZnM6Ly9RbVVNTnB1dWRjNmc1TFhMWXUxVHFGSFhVa3g3clF0dVVQcExqZXh3Q0tINlI5ggABGwr7tRNDSAAGACASAKCQC5t3owTgudh6ullc9j0J2HOslQo2zQThO6xqWlbI+WZFp15b++LEcwTgQKuANwDOxymcsHVcjktlhwTgN6k73yqLLeOOp6e8CrOGTQThOy6ctWadluZ0HSzbKM3RSQAg+2cXtnm2eGMBELAAIgAp7QAdDTAwFxsKMB+kABINdJgQELuvLgiCDXCwoggQT/uvLQiYMJuvLgiFRQUwNvBPhhAvhi2zxZ2zzy4ILI+EMBzH8BygABAYEBAc8Aye1UEQ0C9u2i7fsBkjB/4HAh10nCH5UwINcLH94gghCUapi2uo6oMNMfAYIQlGqYtrry4IHTPwExyAGCEK/5D1dYyx/LP8n4QgFwbds8f+DAAI4r+QGC8MT41yMS7f3vW3vseDO9uxYtFRG9eKkSrtDyY3r2VXKuupSkf9sx4JEw4g4SATptbSJus5lbIG7y0IBvIgGRMuIQJHADBIBCUCPbPA8ByshxAcoBUAcBygBwAcoCUAUg10mBAQu68uCIINcLCiCBBP+68tCJgwm68uCIzxZQA/oCcAHKaCNus5F/kyRus+KXMzMBcAHKAOMNIW6znH8BygABIG7y0IABzJUxcAHKAOLJAfsAEACYfwHKAMhwAcoAcAHKACRus51/AcoABCBu8tCAUATMljQDcAHKAOIkbrOdfwHKAAQgbvLQgFAEzJY0A3ABygDicAHKAAJ/AcoAAslYzAFC7UTQ1AH4Y9IAAZeBAQHXAAEx4DD4KNcLCoMJuvLgids8EgACcMdIBL0='); + let builder = beginCell(); + builder.storeRef(__system); + builder.storeUint(0, 1); + initMyContract_init_args({ $$type: 'MyContract_init_args' })(builder); + const __data = builder.endCell(); + return { code: __code, data: __data }; +} + +const MyContract_errors: { [key: number]: { message: string } } = { + 2: { message: `Stack undeflow` }, + 3: { message: `Stack overflow` }, + 4: { message: `Integer overflow` }, + 5: { message: `Integer out of expected range` }, + 6: { message: `Invalid opcode` }, + 7: { message: `Type check error` }, + 8: { message: `Cell overflow` }, + 9: { message: `Cell underflow` }, + 10: { message: `Dictionary error` }, + 13: { message: `Out of gas error` }, + 32: { message: `Method ID not found` }, + 34: { message: `Action is invalid or not supported` }, + 37: { message: `Not enough TON` }, + 38: { message: `Not enough extra-currencies` }, + 128: { message: `Null reference exception` }, + 129: { message: `Invalid serialization prefix` }, + 130: { message: `Invalid incoming message` }, + 131: { message: `Constraints error` }, + 132: { message: `Access denied` }, + 133: { message: `Contract stopped` }, + 134: { message: `Invalid argument` }, + 135: { message: `Code of a contract was not found` }, + 136: { message: `Invalid address` }, + 137: { message: `Masterchain support is not enabled for this contract` }, +} + +const MyContract_types: ABIType[] = [ + {"name":"StateInit","header":null,"fields":[{"name":"code","type":{"kind":"simple","type":"cell","optional":false}},{"name":"data","type":{"kind":"simple","type":"cell","optional":false}}]}, + {"name":"Context","header":null,"fields":[{"name":"bounced","type":{"kind":"simple","type":"bool","optional":false}},{"name":"sender","type":{"kind":"simple","type":"address","optional":false}},{"name":"value","type":{"kind":"simple","type":"int","optional":false,"format":257}},{"name":"raw","type":{"kind":"simple","type":"slice","optional":false}}]}, + {"name":"SendParameters","header":null,"fields":[{"name":"bounce","type":{"kind":"simple","type":"bool","optional":false}},{"name":"to","type":{"kind":"simple","type":"address","optional":false}},{"name":"value","type":{"kind":"simple","type":"int","optional":false,"format":257}},{"name":"mode","type":{"kind":"simple","type":"int","optional":false,"format":257}},{"name":"body","type":{"kind":"simple","type":"cell","optional":true}},{"name":"code","type":{"kind":"simple","type":"cell","optional":true}},{"name":"data","type":{"kind":"simple","type":"cell","optional":true}}]}, + {"name":"Deploy","header":2490013878,"fields":[{"name":"queryId","type":{"kind":"simple","type":"uint","optional":false,"format":64}}]}, + {"name":"DeployOk","header":2952335191,"fields":[{"name":"queryId","type":{"kind":"simple","type":"uint","optional":false,"format":64}}]}, + {"name":"FactoryDeploy","header":1829761339,"fields":[{"name":"queryId","type":{"kind":"simple","type":"uint","optional":false,"format":64}},{"name":"cashback","type":{"kind":"simple","type":"address","optional":false}}]}, +] + +const MyContract_getters: ABIGetter[] = [ + {"name":"getCounter","arguments":[],"returnType":{"kind":"simple","type":"int","optional":false,"format":257}}, +] + +const MyContract_receivers: ABIReceiver[] = [ + {"receiver":"internal","message":{"kind":"text","text":"increment"}}, + {"receiver":"internal","message":{"kind":"typed","type":"Deploy"}}, +] + +export class MyContract implements Contract { + + static async init() { + return await MyContract_init(); + } + + static async fromInit() { + const init = await MyContract_init(); + const address = contractAddress(0, init); + return new MyContract(address, init); + } + + static fromAddress(address: Address) { + return new MyContract(address); + } + + readonly address: Address; + readonly init?: { code: Cell, data: Cell }; + readonly abi: ContractABI = { + types: MyContract_types, + getters: MyContract_getters, + receivers: MyContract_receivers, + errors: MyContract_errors, + }; + + private constructor(address: Address, init?: { code: Cell, data: Cell }) { + this.address = address; + this.init = init; + } + + async send(provider: ContractProvider, via: Sender, args: { value: bigint, bounce?: boolean| null | undefined }, message: 'increment' | Deploy) { + + let body: Cell | null = null; + if (message === 'increment') { + body = beginCell().storeUint(0, 32).storeStringTail(message).endCell(); + } + if (message && typeof message === 'object' && !(message instanceof Slice) && message.$$type === 'Deploy') { + body = beginCell().store(storeDeploy(message)).endCell(); + } + if (body === null) { throw new Error('Invalid message type'); } + + await provider.internal(via, { ...args, body: body }); + + } + + async getGetCounter(provider: ContractProvider) { + let builder = new TupleBuilder(); + let source = (await provider.get('getCounter', builder.build())).stack; + let result = source.readBigNumber(); + return result; + } + +} \ No newline at end of file diff --git a/src/types/resolveDescriptors.ts b/src/types/resolveDescriptors.ts index 970b4c215..bb025f670 100644 --- a/src/types/resolveDescriptors.ts +++ b/src/types/resolveDescriptors.ts @@ -1,4 +1,4 @@ -import { ASTConstant, ASTField, ASTFunction, ASTInitFunction, ASTNativeFunction, ASTNode, ASTRef, ASTTypeRef, throwError, traverse } from "../grammar/ast"; +import { ASTConstant, ASTField, ASTFunction, ASTInitFunction, ASTNativeFunction, ASTNode, ASTRef, ASTTypeRef, createNode, throwError, traverse } from "../grammar/ast"; import { CompilerContext, createContextStore } from "../context"; import { ConstantDescription, FieldDescription, FunctionArgument, FunctionDescription, InitArgument, InitDescription, printTypeRef, ReceiverSelector, TypeDescription, TypeOrigin, TypeRef, typeRefEquals } from "./types"; import { getRawAST } from "../grammar/store"; @@ -797,7 +797,15 @@ export function resolveDescriptors(ctx: CompilerContext) { const t = types[k]; if (t.kind === 'contract') { if (!t.init) { - throwError('Contract ' + t.name + ' does not have init method', t.ast.ref); + t.init = { + args: [], + ast: createNode({ + kind: 'def_init_function', + args: [], + statements: [], + ref: t.ast.ref + }) as ASTInitFunction + } } } } diff --git a/tact.config.json b/tact.config.json index e0ffabaf2..36238f424 100644 --- a/tact.config.json +++ b/tact.config.json @@ -230,13 +230,21 @@ } }, { - "name": "ternary", - "path": "./src/test/features/ternary.tact", - "output": "./src/test/features/output", - "options": { - "debug": true - } - }, + "name": "ternary", + "path": "./src/test/features/ternary.tact", + "output": "./src/test/features/output", + "options": { + "debug": true + } + }, + { + "name": "implicit-init", + "path": "./src/test/features/implicit-init.tact", + "output": "./src/test/features/output", + "options": { + "debug": true + } + }, { "name": "benchmark_functions", "path": "./src/benchmarks/contracts/functions.tact", From a16926db87ff67e41b56baefaa70a5562c2ff777 Mon Sep 17 00:00:00 2001 From: Gusarich Date: Tue, 5 Mar 2024 23:20:39 +0300 Subject: [PATCH 2/4] add note to changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fb250b6c..f2c8dd2c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- The implicit empty init function is now present by default in the contract if not declared + ### Fixed ## [1.2.0] - 2024-02-29 From 7bf6af0394cc15f590903730a8700202a54c5d42 Mon Sep 17 00:00:00 2001 From: Gusarich Date: Mon, 18 Mar 2024 03:09:12 +0300 Subject: [PATCH 3/4] add negative test case for implicit init feature --- src/test/feature-implicit-init.spec.ts | 9 +++++++++ src/test/features/implicit-init-2.tact | 18 ++++++++++++++++++ src/test/test-tact.config.json | 12 ++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/test/features/implicit-init-2.tact create mode 100644 src/test/test-tact.config.json diff --git a/src/test/feature-implicit-init.spec.ts b/src/test/feature-implicit-init.spec.ts index 6a67575e2..fb5af3af9 100644 --- a/src/test/feature-implicit-init.spec.ts +++ b/src/test/feature-implicit-init.spec.ts @@ -2,6 +2,7 @@ import { toNano } from '@ton/core'; import { ContractSystem } from '@tact-lang/emulator'; import { __DANGER_resetNodeId } from '../grammar/ast'; import { MyContract } from './features/output/implicit-init_MyContract'; +import { run } from '../node'; describe('feature-send', () => { beforeEach(() => { @@ -45,4 +46,12 @@ describe('feature-send', () => { expect(await contract.getGetCounter()).toBe(2n); expect(tracker.collect()).toMatchSnapshot(); }); + + it('should not compile with uninitialized storage fields', async () => { + const result = await run({ + configPath: __dirname + '/test-tact.config.json', + projectNames: ['implicit-init-2'], + }); + expect(result).toBe(false); + }); }); diff --git a/src/test/features/implicit-init-2.tact b/src/test/features/implicit-init-2.tact new file mode 100644 index 000000000..77e361784 --- /dev/null +++ b/src/test/features/implicit-init-2.tact @@ -0,0 +1,18 @@ +import "@stdlib/deploy"; + +contract MyContract with Deployable { + counter: Int = 0; + test_field: Int; + + receive("increment") { + self.counter += 1; + } + + get fun getCounter(): Int { + return self.counter; + } + + get fun getTestField(): Int { + return self.test_field; + } +} \ No newline at end of file diff --git a/src/test/test-tact.config.json b/src/test/test-tact.config.json new file mode 100644 index 000000000..cbabf7f06 --- /dev/null +++ b/src/test/test-tact.config.json @@ -0,0 +1,12 @@ +{ + "projects": [ + { + "name": "implicit-init-2", + "path": "./features/implicit-init-2.tact", + "output": "./features/output", + "options": { + "debug": true + } + } + ] + } \ No newline at end of file From ed3ae39ad1434f1fa05f76915d7b53e38e665229 Mon Sep 17 00:00:00 2001 From: Gusarich Date: Thu, 21 Mar 2024 18:37:53 +0300 Subject: [PATCH 4/4] add check for the error message --- src/test/feature-implicit-init.spec.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/test/feature-implicit-init.spec.ts b/src/test/feature-implicit-init.spec.ts index fb5af3af9..de50a1197 100644 --- a/src/test/feature-implicit-init.spec.ts +++ b/src/test/feature-implicit-init.spec.ts @@ -3,11 +3,25 @@ import { ContractSystem } from '@tact-lang/emulator'; import { __DANGER_resetNodeId } from '../grammar/ast'; import { MyContract } from './features/output/implicit-init_MyContract'; import { run } from '../node'; +import { consoleLogger } from '../logger'; describe('feature-send', () => { + beforeAll(() => { + jest.spyOn(consoleLogger, 'error').mockImplementation(() => {}); + }); + beforeEach(() => { __DANGER_resetNodeId(); }); + + afterAll(() => { + (consoleLogger.error as jest.Mock).mockRestore(); + }); + + afterEach(() => { + (consoleLogger.error as jest.Mock).mockClear(); + }); + it('should deploy', async () => { // Init const system = await ContractSystem.create(); @@ -23,6 +37,7 @@ describe('feature-send', () => { expect(await contract.getGetCounter()).toBe(0n); expect(tracker.collect()).toMatchSnapshot(); }); + it('should increment counter', async () => { // Init const system = await ContractSystem.create(); @@ -52,6 +67,9 @@ describe('feature-send', () => { configPath: __dirname + '/test-tact.config.json', projectNames: ['implicit-init-2'], }); + expect((consoleLogger.error as jest.Mock).mock.lastCall[0]).toContain( + 'Field test_field is not set' + ); expect(result).toBe(false); }); });