This repository stores the source code for tvm_linker utility. It takes TVM (https://test.ton.org/tvm.pdf) assembly source code of TON smart contract, compiles it and links its parts, adds standard selector and runtime and stores it into binary TVC file. Also, it can immediately execute a smart contract by emulating the compute phase of TON transaction.
TVM assembly can be generated by one of TONLabs compilers:
- TON solidity compiler (https://github.com/tonlabs/TON-Solidity-Compiler)
- C and C++ compiler for TVM (https://github.com/tonlabs/TON-Compiler)
- Latest version of Rust
- Cargo tool Get them here
cd tvm_linker && cargo update && cargo build [--release]
tvm_linker has several modes of work:
tvm_linker compile [--lib <lib_file>] [--abi-json <abi_file>] [--genkey | --setkey <keyfile>] [-w <workchain_id>] [--debug] <source>
Here source
is a name of tvm assembly source file, library
is a runtime library file (can be more than one: --lib
should be supplied for every file). If --lib
option is not specified linker looks for environment variable TVM_LINKER_LIB_PATH
,
if it is set that path is used to load a library.
If there is an ABI file, it is better to use --abi-json
option to supply a contract ABI file. Function ID's are generated according to function signatures in the ABI.
If neither -a
nor --abi-json
option is specified, linker checks whether file source
(without extension) + .abi.json
exists. If file exists, linker loads ABI from it.
Linker generates an address.tvc
file, where address
is a hash from initial data and code of the contract.
Linker prints contract address in different formats: raw and user-friendly (testnet and mainnet). Define the workchain ID option -w
to generate proper user-friendly address. -1 is used by default.
To generate a new keypair and put the public key to the contract:
tvm_linker compile <source> --genkey <key_file>
where key_file
is a name of the file to store public and private keys. The linker will generate 2 files: key_file.pub
for public key and key_file
for private key.
To load existing keypair use:
tvm_linker compile <source> --setkey <key_file>
To use this method, call
tvm_linker decode [--tvc] boc-file
If --tvc
is omitted, boc-file
is a file with a serialized message, otherwise it is a contract tvc
file.
First, generate a contract as described in 1). Then use message
subcommand to create external inbound message in boc format:
tvm_linker message <contract-address> [--init] [--data] [-w]
tvm_linker message <contract-address> [--init] --abi-json <abi_file> --abi-method <method_name> --abi-params {json_with_params} [-w]
contract-address
- the name of the compiled contract file without extension. The contract .tvc file should be placed in the current directory.
To create a constructor message
with contract's code and data, use --init
option.
Additionally, you can add a raw body to the message. Use the --data
option:
tvm_linker message <contract-address> --data XXXX...
Instead of XXXX...
, specify the necessary message body in hex format.
Or make a message with ABI call using combination of options:
--abi-json <abi_file>
- path to a .json with contract interface described according to ABI specification;--abi-method <method-name>
- name of the contract method to call;--abi-params {<json-string-with-params>}
- arguments of the method declared in json like this:{"arg_a": "0x1234", "arg_b": "x12345678"}
.
By default, -1 is used as a workchain id in contract address. To use another one, use -w
option:
tvm_linker message -w 0
Linker can emulate compute phase of blockchain transaction. It is useful for contract debugging.
tvm_linker test <contract-address> --body XXXX... [--sign key-file] [--trace] [--decode-c6] [--internal <value>] [--src address] [--now unixtime] [-s source-file] [--balance <value>]
Loads contract from file by contract address address
and emulates contract call sending external inbound message (by default) with body defined after --body
parameter to the contract. XXXX...
is a hex string.
If --sign
specified, the body will be signed with the private key from key-file
file.
Use --trace
flag to trace VM execution: stack, registers and gas will be printed after each executed VM command.
Use --decode-c6
to see output actions in user-friendly format.
Use --balance <value>
to define account balance in nanograms. It will be available at the bottom of initial stake and in SmartContractInfo tuple from c7 register .
Use --internal
to send internal message to the contract with defined nanograms in value
. By default, source address in internal message in zero address (0000...0000
), to define another address use option --src <address>
, where address should be in the format : (i.e. "0:1122...AABB").
Account and message balance can have extended format with extra currencies: { "main": int, "extra": {"i": int, ...} }
.
Example: --internal 100000 --src "0:6011b66a47238cf992f1033fe6aff00ce0f850df387ee92468d9c26b5564ba53"
Use --now <unixtime>
option to define transaction creation time. By default, current time is used.
Use --bounced
flag to emulate bounced internal message, use this flag only with --internal
option.
An ABI body can be generated if abi-params
, abi-json
and abi-method
will be used instead of --body XXXX...
.
If --body
is used, contract's public function ids can be encoded by their names using $...$
syntax:$name:[0len][type]$
,
where name
is a name of public function, len
- length in chars of the id (if len
is bigger than name
's length in chars than
zeros will be added on the left side to fit required length), type
can be x
or X
- hexadecimal integer in lowercase or uppercase. You have to set -s source
option when you use
Example:
tvm_linker address test --body 00$main$ -s source //main id will be inserted as decimal string. Dont use this case, just as example
tvm_linker address test --body 00$main:08X$ -s source
tvm_linker address test --body 00$main:X$ -s source
tvm_linker address test --body 00$main:x$ -s source
The --body-from-boc
option is analogous to --body
but extracts the message body from the specified message boc file.
tvm_linker init <tvc_file> <data_json> <abi_file>
Updates contract's static state variables (see section data
in *.abi.json
file) with values
defined in data_json
argument.
Example:
tvm_linker init contract.tvc '{"var1": 10}' contract.abi.json
There are a number of tools under the disasm
umbrella:
dump
outputs a pseudo-graphical representation of a tree of cells.
solidity
and fun_c
subcommands both disassemble a tvc produced by Solidity and FunC compilers respectively.
graphviz
produces an output in dot format for generation of graphical DAG representation of a tvc.
Use tvm_linker --help
for detailed description about all options, flags and subcommands.
As a temporary measure, some LLVM-assembler like input is used. The source code should contain several function types:
- .selector - contract's entry point. This function should be short.
.selector
<code here>
- .globl - general purpose functions; can be public or private.
.globl x
[.public x]
.type x, @function
x:
<code here>
-
.internal - special functions, which are used only by contract's runtime. There are some wellknown internal functions:
main_external, main_internal, main_ticktock, main_split, main_merge
Get more documents at docs.ton.dev and check our YouTube Channel for tutorials. Stay tuned.