📜 ⬆️ ⬇️

Test client TON (Telegram Open Network) and new language Fift for smart contracts

More than a year ago it became known about the plans of the Telegram messenger to release its own decentralized network Telegram Open Network . Then a voluminous technical document became available that was supposedly written by Nikolai Durov and described the structure of the future network. For those who missed it, I recommend that you familiarize yourself with my retelling of this document ( part 1 , part 2 ; the third part, alas, is still gathering dust in drafts).


Since then, there has been no significant news about the development status of TON until a couple of days ago (in one of the unofficial channels ) there was a link to the page https://test.ton.org/download.html , where the following is posted:


â—¦ ton-test-liteclient-full.tar.xz - light client sources for the TON test network;
â—¦ ton-lite-client-test1.config.json - configuration file for connecting to the test network;
â—¦ README - information about building and running the client;
â—¦ HOWTO - step-by-step instructions on creating a smart contract using a client;
â—¦ ton.pdf is an updated document (dated March 2, 2019) with a technical review of the TON network;
â—¦ tvm.pdf - technical description of TVM (TON Virtual Machine, TON virtual machine);
â—¦ tblkch.pdf - technical description of the blockchain TON;
â—¦ fiftbase.pdf - description of the new language Fift, designed to create smart contracts in TON.


I repeat, there was no official confirmation of the page and all these documents by the Telegram, but the volume of these materials makes them quite plausible. Launch a published client at your own risk .


Build a test client


To begin with, we will try to build and run a test client - the benefit, the README describes this simple process in detail. I will do this on the example of macOS 10.14.5, I can not vouch for the success of the assembly on other systems.


  1. Download and unpack the archive with source code . It is important to download the latest version, since backward compatibility is not guaranteed at this stage.


  2. Make sure that the latest versions of make, cmake (version 3.0.2 or higher), OpenSSL (including the C header files), g ++ or clang are installed on the system. I did not have to reinstall anything, everything gathered right away.


  3. Suppose the sources are unpacked into the ~/lite-client folder. Separately from it, we create an empty folder for the assembled project (for example, ~/liteclient-build ), and from it ( cd ~/liteclient-build ) we call the following commands:


     cmake ~/lite-client cmake --build . --target test-lite-client 

    Successful customer build

    To build the Fift interpreter for smart contracts (see below), also call


     cmake --build . --target fift 

  4. Download the current configuration file to connect to the test network and put it in the folder with the assembled client.


  5. Done , you can run the client:


     ./test-lite-client -C ton-lite-client-test1.config.json 


If everything is done correctly, then you should see something like this:


Client launch


Available commands, as you can see, are few:


â—¦ help - display this list of commands;
â—¦ quit - exit;
â—¦ time - show the current time on the server;
◦ status — show connection status and local database;
â—¦ last - update the blockchain status (load the last block). This command is important to perform before any requests, to be sure that you see exactly the current state of the network.
â—¦ sendfile <filename> - upload local file to TON network. This is how the interaction with the network takes place, including, for example, the creation of new smart contracts and requests to transfer funds between accounts;
â—¦ getaccount <address> - show the current (at the time of the last command) the status of the account with the specified address;
â—¦ privkey <filename> - load a private key from a local file.


If, when the client starts, you transfer the folder to it using the -D option, then it will add the last master unit block into it:


 ./test-lite-client -C ton-lite-client-test1.config.json -D ~/ton-db-dir 

Now we can move on to more interesting things - learn the Fift language, try to compile a smart contract (for example, create a test wallet), upload it to the network and try transferring funds between accounts.


Fift language


From the document fiftbase.pdf you can find out that to create smart contracts, the Telegram team created a new stack language Fift (apparently, from the numeral fifth , by analogy with Forth, a language with which Fift has a lot in common).


The document is quite lengthy, on 87 pages, and I will not begin to retell in detail its content within the framework of this article (at least, because I did not finish reading it :). I’ll dwell on the main points and give a couple of code examples in this language.


At a basic level, the Fift syntax is quite simple: its code consists of words , usually separated by spaces or line breaks (a special case: some words do not require a separator after themselves). Any word is a case-sensitive sequence of characters, to which some definition corresponds (roughly speaking, what the interpreter should do when it encounters this word). If the word is not defined, the interpreter tries to parse it as a number and put it on the stack. By the way, the numbers here are - suddenly - 257-bit integers, but there are no fractional ones at all - more precisely, they immediately turn into a pair of integers that form the numerator and denominator of a rational fraction.


Words usually interact with the values ​​at the top of the stack. A separate type of words - prefix - does not use the stack, but the characters following it from the source file. For example, string literals are implemented this way - the character "quotation mark" ( " ) is a prefix word that searches for the next (closing) quotation mark and puts a string between them on the stack. Single-line ( // ) and multi-line ( /* ) behave in the same way. comments.


At this almost all the internal structure of the language ends. Everything else (including control constructs) is defined as words (either internal, such as arithmetic operations and the definition of new words; or defined in the “standard library” Fift.fif , which lies in the crypto/fift in the source).


A simple example of a program on Fift:


 { dup =: x dup * =: y } : setxy 3 setxy x . y . xy + . 7 setxy x . y . xy + . 

The first line defines the new word setxy (note the prefix { , which creates a block before the closing } and the prefix : which actually defines the word). setxy takes a number from the top of the stack, defines (or redefines) it as a global constant x , and the square of this number - as a constant y (given that constant values ​​can be redefined, I would rather call them variables, but I follow the naming in the language).


In the next two lines, a number is put on the stack, setxy is setxy , then the values ​​of the x , y constants are output (the word is used for output . ), Both constants are placed on the stack, added up, and the result is also output. As a result, we will see:


 3 9 12 ok 7 49 56 ok 

(The “ok” line is displayed by the interpreter when it finishes processing the current line in interactive input mode)


Well, a full sample code:


 "Asm.fif" include -1 constant wc // create a wallet in workchain -1 (masterchain) // Create new simple wallet <{ SETCP0 DUP IFNOTRET INC 32 THROWIF // return if recv_internal, fail unless recv_external 512 INT LDSLICEX DUP 32 PLDU // sign cs cnt c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk s1 s2 XCPU // sign cs cnt pubk cnt' cnt EQUAL 33 THROWIFNOT // ( seqno mismatch? ) s2 PUSH HASHSU // sign cs cnt pubk hash s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk CHKSIGNU // pubk cs cnt ? 34 THROWIFNOT // signature mismatch ACCEPT SWAP 32 LDU NIP DUP SREFS IF:<{ 8 LDU LDREF // pubk cnt mode msg cs s0 s2 XCHG SENDRAWMSG // pubk cnt cs ; ( message sent ) }> ENDS INC NEWC 32 STU 256 STU ENDC c4 POPCTR }>c // code <b 0 32 u, newkeypair swap dup constant wallet_pk "new-wallet.pk" B>file B, b> // data // no libraries <bb{00110} s, rot ref, swap ref, b> // create StateInit dup ."StateInit: " <s csr. cr dup hash dup constant wallet_addr ."new wallet address = " wc . .": " dup x. cr wc over 7 smca>$ type cr 256 u>B "new-wallet.addr" B>file <b 0 32 u, b> dup ."signing message: " <s csr. cr dup hash wallet_pk ed25519_sign_uint rot <bb{1000100} s, wc 8 i, wallet_addr 256 u, b{000010} s, swap <ss, b{0} s, swap B, swap <ss, b> dup ."External message for initialization is " <s csr. cr 2 boc+>B dup Bx. cr "new-wallet-query.boc" tuck B>file ."(Saved to file " type .")" cr 

This scary looking file is designed to create a smart contract - it will be placed in the new-wallet-query.boc after execution. Please note that another one is used here, the assembler language for the TON Virtual Machine (I will not dwell on it in detail), whose instructions will be placed on the blockchain.


Thus, the assembler for TVM is written in Fift - the sources of this assembler are in the crypto/fift/Asm.fif and are connected at the beginning of the above code snippet.


What can I say, apparently, Nikolai Durov just loves to create new programming languages ​​:)


Creating a smart contract and interacting with TON


So, suppose we assembled the TON client and the Fift interpreter, as described above, and got to know the language. How to create a smart contract now? This is covered in the HOWTO file attached to the sources.


TON accounts


As I described in the TON review , this network contains more than one blockchain - there is one common, so-called. “Master”, as well as an arbitrary number of additional “workers”, identified by a 32-bit number. The masterchain has the identifier -1, except that it can also use the “base” workpiece with the identifier 0. Each workpiece can have its own configuration. Internally, each workpiece splits into shardchains, but this is already a part of the implementation, which need not be kept in mind.


Within one workplace there are a lot of accounts that have their account_id identifiers. For master and zero workflow, they are 256 bits long. Thus, the account identifier is written, for example, as follows:


 -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

This is the “raw” format: first the workflow ID, then the colon, and the account ID in hexadecimal.


In addition, there is a shortened format - the workman number and the address of the account are encoded in binary form, the checksum is added to them and all of this is encoded in Base64:


 Ef+BVndbeTJeXWLnQtm5bDC2UVpc0vH2TF2ksZPAPwcODSkb 

Knowing this record format, we can request the current state of an account through a test client using the command


 getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

We get something like this:


 [ 3][t 2][1558746708.815218925][test-lite-client.cpp:631][!testnode] requesting account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D [ 3][t 2][1558746708.858564138][test-lite-client.cpp:652][!testnode] got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F account state is (account addr:(addr_std anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D) storage_stat:(storage_info used:(storage_used cells:(var_uint len:1 value:3) bits:(var_uint len:2 value:539) public_cells:(var_uint len:0 value:0)) last_paid:0 due_payment:nothing) storage:(account_storage last_trans_lt:74208000003 balance:(currencies grams:(nanograms amount:(var_uint len:7 value:999928362430000)) other:(extra_currencies dict:hme_empty)) state:(account_active ( split_depth:nothing special:nothing code:(just value:(raw@^Cell x{} x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} )) data:(just value:(raw@^Cell x{} x{0000000D} )) library:hme_empty)))) x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C000000000000000451C90E00DC0E35B7DB5FB8C134_} x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} x{0000000D} -client.cpp: [ 3][t 2][1558746708.815218925][test-lite-client.cpp:631][!testnode] requesting account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D [ 3][t 2][1558746708.858564138][test-lite-client.cpp:652][!testnode] got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F account state is (account addr:(addr_std anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D) storage_stat:(storage_info used:(storage_used cells:(var_uint len:1 value:3) bits:(var_uint len:2 value:539) public_cells:(var_uint len:0 value:0)) last_paid:0 due_payment:nothing) storage:(account_storage last_trans_lt:74208000003 balance:(currencies grams:(nanograms amount:(var_uint len:7 value:999928362430000)) other:(extra_currencies dict:hme_empty)) state:(account_active ( split_depth:nothing special:nothing code:(just value:(raw@^Cell x{} x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} )) data:(just value:(raw@^Cell x{} x{0000000D} )) library:hme_empty)))) x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C000000000000000451C90E00DC0E35B7DB5FB8C134_} x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} x{0000000D} for -1: 8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355): F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296: 1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and [ 3][t 2][1558746708.815218925][test-lite-client.cpp:631][!testnode] requesting account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D [ 3][t 2][1558746708.858564138][test-lite-client.cpp:652][!testnode] got account state for -1:8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D with respect to blocks (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F and (-1,8000000000000000,72355):F566005749C1B97F18EDE013EBA7A054B9014961BC1AD91F475B9082919A2296:1BD5DE54333164025EE39D389ECE2E93DA2871DA616D488253953E52B50DC03F account state is (account addr:(addr_std anycast:nothing workchain_id:-1 address:x8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D) storage_stat:(storage_info used:(storage_used cells:(var_uint len:1 value:3) bits:(var_uint len:2 value:539) public_cells:(var_uint len:0 value:0)) last_paid:0 due_payment:nothing) storage:(account_storage last_trans_lt:74208000003 balance:(currencies grams:(nanograms amount:(var_uint len:7 value:999928362430000)) other:(extra_currencies dict:hme_empty)) state:(account_active ( split_depth:nothing special:nothing code:(just value:(raw@^Cell x{} x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} )) data:(just value:(raw@^Cell x{} x{0000000D} )) library:hme_empty)))) x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C000000000000000451C90E00DC0E35B7DB5FB8C134_} x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} x{0000000D} 

We see the structure that is stored in the DHT of the specified workman. For example, the current balance of the account is in the storage.state.code , the smart contract code in storage.state.data and its current data in storage.state.data . Please note that the TON data storage cell, the cells, is tree-like; each cell can have its own data as well as child cells. This is shown as indents in the last lines.


Build a smart contract


Now let's create such a structure ourselves (it is called BOC - bag of cells ) using the Fift language. Fortunately, you will not have to write a smart contract yourself - in the crypto/block folder from the archive with source codes there is a file new-wallet.fif , which will help us create a new wallet. Copy it to the folder with the client ( ~/liteclient-build , if you acted according to the instructions above). I cited its contents above as an example of code on Fift.


Execute this file as follows:


 ./crypto/fift -I"<source-directory>/crypto/fift" new-wallet.fif 

Here, <source-directory> must be replaced with the path to the unpacked sources (the "~" symbol here, unfortunately, cannot be used, the full path is needed). Instead of using the -I you can define the FIFTPATH environment FIFTPATH and put this path in it.


Since we started Fift with the file name new-wallet.fif , it will execute it and finish. If you omit the file name, you can play with the interpreter in interactive mode.


After execution, something like this should be displayed in the console:


 StateInit: x{34_} x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B} new wallet address = -1 : 4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ signing message: x{00000000} External message for initialization is x{89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001_} x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B} B5EE9C724104030100000000D60002CF89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001001020084FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED5400480000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B6290698B (Saved to file new-wallet-query.boc) } StateInit: x{34_} x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B} new wallet address = -1 : 4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ signing message: x{00000000} External message for initialization is x{89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001_} x{FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} x{0000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B} B5EE9C724104030100000000D60002CF89FEE120E20C7E953E31546F64C23CD654002C1AA919ADD24DB12DDF85C6F3B58AE41198A28AD8DAF3B9588E7A629252BA3DB88F030D00BC1016110B2073359EAC3C13823C53245B65D056F2C070B940CDA09789585935C7ABA4D2AD4BED139281CFA1200000001001020084FF0020DDA4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED5400480000000055375F730EDC2292E8CB15C42E8036EE9C25AA958EE002D2DE48A205E3A3426B6290698B (Saved to file new-wallet-query.boc) 

This means that the wallet with the identifier -1:4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 (or, which is the same, 0f9PzVILj8yglrVn1zS-NSjtxr7QBfaTCp7JrBqnFPIR8nhZ The corresponding code will be in the file new-wallet-query.boc , its address will be in new-wallet.addr , and the private key will be in new-wallet.pk (be careful, re-running the script will overwrite these files).


Of course, the TON network does not know about this wallet yet, it is stored only in the form of these files. Now you need to upload it to the network. True, the problem is that to create a smart contract you need to pay a commission, and the balance of your account is still zero.


In operation, this problem will be solved by buying grams on the exchange (or transfer from another wallet). Well, in the current test mode, a special smart contract has been established, from which you can ask for up to 20 grams just like that.


Forming a request to someone else's smart contract


Request to the smart contract, distributing grams to the left and right, do so. In the same crypto/block folder we find the file testgiver.fif :


 // "testgiver.addr" file>B 256 B>u@ 0x8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d dup constant wallet_addr ."Test giver address = " x. cr 0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 constant dest_addr -1 constant wc 0x00000011 constant seqno 1000000000 constant Gram { Gram swap */ } : Gram*/ 6.666 Gram*/ constant amount // bx --> b' ( serializes a Gram amount ) { -1 { 1+ 2dup 8 * ufits } until rot over 4 u, -rot 8 * u, } : Gram, // create a message (NB: 01b00.., b = bounce) <bb{010000100} s, wc 8 i, dest_addr 256 u, amount Gram, 0 9 64 32 + + 1+ 1+ u, "GIFT" $, b> <b seqno 32 u, 1 8 u, swap ref, b> dup ."enveloping message: " <s csr. cr <bb{1000100} s, wc 8 i, wallet_addr 256 u, 0 Gram, b{00} s, swap <ss, b> dup ."resulting external message: " <s csr. cr 2 boc+>B dup Bx. cr "wallet-query.boc" B>file 

We will also save it in the folder with the collected client, but we will fix the fifth line - before the line " constant dest_addr ". Replace it with the address of the wallet that you created before (full, not abbreviated). "-1:" does not need to be written at the beginning; instead, put "0x" at the beginning.


You can also change the line 6.666 Gram*/ constant amount - this is the amount in grams that you request (no more than 20). Even if you specify an integer, leave a decimal point.


Finally, you need to correct the line 0x00000011 constant seqno . The first number here is the current sequence number, which is stored in the account issuing the grams. Where to get it from? As mentioned above, launch the client and execute:


 last getaccount -1:8156775b79325e5d62e742d9b96c30b6515a5cd2f1f64c5da4b193c03f070e0d 

At the very end in the data of the smart contract will be


 ... x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} x{0000000D} 

The number 0000000D (you will have more) is the sequence number, which should be substituted into testgiver.fif .


Everything, save the file and run ( ./crypto/fift testgiver.fif ). At the output we get the file wallet-query.boc . This is the generated message to someone else's smart contract - the request “transfer so many grams to such an account”.


With the help of the client, we upload it to the network:


 > sendfile wallet-query.boc [ 1][t 1][1558747399.456575155][test-lite-client.cpp:577][!testnode] sending query from file wallet-query.boc [ 3][t 2][1558747399.500236034][test-lite-client.cpp:587][!query] external message status is 1 

If we now call last , and then again request the status of the account from which we asked for grams, then we should see that his sequence number increased by one, which means that he sent money to our account.


The last step remains - load the code of our wallet (its balance has already been replenished, but without the smart contract code we cannot manage it). sendfile new-wallet-query.boc - and that’s it, you have your own wallet on the TON network (albeit only a test one for now).


Create outbound transactions


To transfer money from the balance of the created account, there is a file crypto/block/wallet.fif , which also needs to be placed in the folder with the collected client.


Similar to the previous steps, you need to correct the amount you transfer, the destination address (dest_addr), and seqno of your wallet (it is 1 after the wallet initialization and increases by 1 after each outgoing transaction - you can see it by requesting your account status) . For tests, you can use, for example, my wallet - 0x4fcd520b8fcca096b567d734be3528edc6bed005f6930a9ec9ac1aa714f211f2 .


When running ( ./crypto/fift wallet.fif ), the script will take the address of your wallet (from where you are transferring) and its private key from the files new-wallet.addr and new-wallet.pk , and write the received message to new-wallet-query.boc .


As before, to directly execute a transaction, call sendfile new-wallet-query.boc in the client. After that, do not forget to update the state of the blockchain ( last ) and check that the balance and seqno of our wallet have changed ( getaccount <account_id> ).


Account Description


That's all, now we are able to create smart contracts in TON and send requests to them. As you can see, the current functionality is already enough to, for example, make a more friendly wallet with a graphical interface (however, it is expected that it will already be available as part of the messenger).


')

Source: https://habr.com/ru/post/453714/


All Articles