mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-05-06 14:58:31 +00:00
Merge pull request #4751 from yash0501/master
[tact/en] Update Tact doc with all examples
This commit is contained in:
commit
88a428ca60
@ -4,6 +4,7 @@ filename: tact.tc
|
|||||||
contributors:
|
contributors:
|
||||||
- ["Tal Kol", "https://www.orbs.com/"]
|
- ["Tal Kol", "https://www.orbs.com/"]
|
||||||
- ["Kirill Malev", "https://fslabs.io"]
|
- ["Kirill Malev", "https://fslabs.io"]
|
||||||
|
- ["Yash Garg", "https://github.com/yash0501"]
|
||||||
---
|
---
|
||||||
|
|
||||||
Tact language is used to program smart contracts on the
|
Tact language is used to program smart contracts on the
|
||||||
@ -39,8 +40,8 @@ This is a simple counter contract that allows users to increment its value.
|
|||||||
This contract has a state variable `val` that persists between contract calls
|
This contract has a state variable `val` that persists between contract calls
|
||||||
|
|
||||||
- the counter value. When persisted, this variable is encoded as `uint32` -
|
- the counter value. When persisted, this variable is encoded as `uint32` -
|
||||||
a 32-bit unsigned integer. Contracts pay rent in proportion to the amount
|
a 32-bit unsigned integer. Contracts pay rent in proportion to the amount
|
||||||
of persistent space they consume, so compact representations are encouraged.
|
of persistent space they consume, so compact representations are encouraged.
|
||||||
|
|
||||||
State variables should be initialized in `init()` that runs on deployment of
|
State variables should be initialized in `init()` that runs on deployment of
|
||||||
the contract.
|
the contract.
|
||||||
@ -220,19 +221,371 @@ contract Integers with Deployable {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Bools, Addresses, Strings, Operators and Constants
|
||||||
|
|
||||||
|
### Bool
|
||||||
|
|
||||||
|
Bool can be used for boolean variables
|
||||||
|
|
||||||
|
```js
|
||||||
|
b1: Bool = true;
|
||||||
|
b2: Bool = false;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Address
|
||||||
|
|
||||||
|
Address is another primitive data type. It represents standard addresses on
|
||||||
|
the TON blockchain.
|
||||||
|
TON is divided into multiple chains called workchains. One of the internal
|
||||||
|
fields of the address is the workchain id:
|
||||||
|
0 - The standard workchain, for regular users. Your contracts will be here.
|
||||||
|
-1 - The masterchain, usually for validators.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// bouncable (same foundation wallet)
|
||||||
|
a1: Address = address("EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N");
|
||||||
|
// non-bounceable (same foundation wallet)
|
||||||
|
a2: Address = address("UQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqEBI");
|
||||||
|
```
|
||||||
|
|
||||||
|
### String
|
||||||
|
|
||||||
|
Tact has basic support for strings. Strings support unicode and don't
|
||||||
|
have any special escape characters like \n.
|
||||||
|
Strings are immutable. Once a sequence of characters is created, this
|
||||||
|
sequence cannot be modified.
|
||||||
|
If you need to concatenate strings in run-time, you can use a StringBuilder.
|
||||||
|
This object handles gas efficiently and supports append() of various types to
|
||||||
|
the string.
|
||||||
|
|
||||||
|
```js
|
||||||
|
s1: String = "hello world";
|
||||||
|
sb: StringBuilder = beginString();
|
||||||
|
sb.append(self.s1);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integer Operations
|
||||||
|
|
||||||
|
Addition, subtraction, multiplication, division, modulo,
|
||||||
|
shift left and right, minimum and maximum numbers, absolute value
|
||||||
|
|
||||||
|
```js
|
||||||
|
i: Int = -12; // temporary variable, runtime Int type is always int257
|
||||||
|
i = i1 * 3 + (i2 - i); // basic math expressions
|
||||||
|
i = i1 % 10; // modulo (remainder after division), 3001 % 10 = 1
|
||||||
|
i = i1 / 1000; // integer division (truncation toward zero), 3001 / 1000 = 3
|
||||||
|
i = i1 >> 3; // shift right (multiply by 2^n)
|
||||||
|
i = i1 << 2; // shift left (divide by 2^n)
|
||||||
|
i = min(i2, 11); // minimum between two numbers
|
||||||
|
i = max(i2, 66); // maximum between two numbers
|
||||||
|
i = abs(-1 * i2); // absolute value
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constants
|
||||||
|
|
||||||
|
Unlike variables, constants cannot change. Their values are
|
||||||
|
calculated in compile-time and cannot change during execution.
|
||||||
|
|
||||||
|
```js
|
||||||
|
const StateUnpaid: Int = 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getters, Receivers and Messages
|
||||||
|
|
||||||
|
### Getters
|
||||||
|
|
||||||
|
Getters are special contract functions that allow users to query
|
||||||
|
information from the contract.
|
||||||
|
Contract methods starting with the prefix get fun are all getters.
|
||||||
|
Calling getters is free and does not cost gas.
|
||||||
|
Getters are read-only, they cannot change the contract persistent state.
|
||||||
|
A contract cannot execute a getter of another contract. Getters are only
|
||||||
|
executable by end-users off-chain.
|
||||||
|
|
||||||
|
```js
|
||||||
|
count: Int as uint32 = 17;
|
||||||
|
|
||||||
|
get fun counter(): Int {
|
||||||
|
return self.count;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Receivers
|
||||||
|
|
||||||
|
Contract methods named receive() are the handlers that process
|
||||||
|
each incoming message type.
|
||||||
|
Tact will automatically route every incoming message to the correct receiver
|
||||||
|
listening for it according to its type. A message is only handled by one receiver.
|
||||||
|
|
||||||
|
Handler for "increment" textual message - this is a textual string message,
|
||||||
|
these cannot carry input arguments
|
||||||
|
|
||||||
|
```js
|
||||||
|
receive("increment") {
|
||||||
|
self.val = self.val + 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Messages
|
||||||
|
|
||||||
|
Messages are defined using the message keyword. They can carry input
|
||||||
|
arguments. For integers, you must define the encoding size, just like in
|
||||||
|
state variables.
|
||||||
|
|
||||||
|
Handler for the "Add" message - this is a binary message that has an input
|
||||||
|
argument (amount)
|
||||||
|
|
||||||
|
```js
|
||||||
|
receive(msg: Add) {
|
||||||
|
self.val = self.val + msg.amount;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structs
|
||||||
|
|
||||||
|
Structs allow you to combine multiple primitives together in a more semantic way.
|
||||||
|
Structs can define complex data types that contain multiple fields of
|
||||||
|
different types. They can also be nested.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// Normal struct
|
||||||
|
struct Point {
|
||||||
|
x: Int as int64;
|
||||||
|
y: Int as int64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nested struct
|
||||||
|
struct Params {
|
||||||
|
name: String = "Satoshi"; // default value
|
||||||
|
age: Int? = null; // optional field
|
||||||
|
point: Point; // nested structs
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Message Sender and Throwing Errors
|
||||||
|
|
||||||
|
### Message Sender
|
||||||
|
|
||||||
|
Every incoming message is sent from some contract that has
|
||||||
|
an address. You can query the address of the message sender by calling sender()
|
||||||
|
|
||||||
|
```js
|
||||||
|
deployer: Address = sender();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
When an error is thrown, the transaction reverts. By writing a
|
||||||
|
require() on a condition that isn't met
|
||||||
|
|
||||||
|
```js
|
||||||
|
require(self.val < 5, "Counter is too high");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Messages Between Contracts, Sending and Receiving TON Coins
|
||||||
|
|
||||||
|
### Messages Between Contracts
|
||||||
|
|
||||||
|
Different contracts can only communicate with
|
||||||
|
each other by sending each other messages.
|
||||||
|
|
||||||
|
This example sends a message to the to address with value of 1 TON and body
|
||||||
|
of a comment with a string "Hello, World!".
|
||||||
|
SendIgnoreErrors means that even when error occurs during message sending
|
||||||
|
next messages would be sent anyway.
|
||||||
|
|
||||||
|
```js
|
||||||
|
let to: Address = ...;
|
||||||
|
let value: Int = ton("1");
|
||||||
|
send(SendParameters{
|
||||||
|
to: to, // address of receiver
|
||||||
|
value: value, // amount of TON you want to send
|
||||||
|
mode: SendIgnoreErrors, // 8-bit flag configuring how to send message
|
||||||
|
bounce: true, // if set to true (default) then message
|
||||||
|
// will be bounced back to sender
|
||||||
|
body: "Hello, World!".asComment() // message body as Cell
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Receiving TONs
|
||||||
|
|
||||||
|
You can query the contract balance with myBalance() - note
|
||||||
|
that the value is in nano-tons (like cents, just with 9 decimals). The balance
|
||||||
|
already contains the incoming message value.
|
||||||
|
You can also get the incoming TON balance with context().value
|
||||||
|
|
||||||
|
```js
|
||||||
|
val: Int as int64 = myBalance()
|
||||||
|
// or
|
||||||
|
// print how much TON coin were sent with this message
|
||||||
|
dump(context().value);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sending TONs
|
||||||
|
|
||||||
|
We can send any amount of TON to any address just like we created
|
||||||
|
a send call between different contracts
|
||||||
|
|
||||||
|
Send mode SendRemainingValue will add to the outgoing value any excess left
|
||||||
|
from the incoming message after all gas costs are deducted from it.
|
||||||
|
|
||||||
|
```js
|
||||||
|
amount: Int as coins = ton("1");
|
||||||
|
send(SendParameters{
|
||||||
|
to: sender(),
|
||||||
|
bounce: true,
|
||||||
|
value: amount,
|
||||||
|
mode: SendRemainingValue + SendIgnoreErrors
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## If/Else statements and Loops
|
||||||
|
|
||||||
|
### If
|
||||||
|
|
||||||
|
Tact supports if statements in a similar syntax to most programming
|
||||||
|
languages. Curly braces are required.
|
||||||
|
We can have the else and else if similar to other programming languages.
|
||||||
|
|
||||||
|
```js
|
||||||
|
if (val > 1000) {
|
||||||
|
dump("larger than 1000");
|
||||||
|
} else if (val > 500) {
|
||||||
|
dump("between 500 and 1000");
|
||||||
|
} else {
|
||||||
|
dump("smaller than 500");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loops
|
||||||
|
|
||||||
|
Tact does not support traditional 'for' loops, 'break' and 'continue'
|
||||||
|
statements in loops.
|
||||||
|
The repeat loop statement input number must fit within an int32.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// repeat exactly 10 times
|
||||||
|
|
||||||
|
repeat (10) {
|
||||||
|
i = i + 1;
|
||||||
|
sum = sum + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// While loop
|
||||||
|
|
||||||
|
let x: Int = 10;
|
||||||
|
while(x > 0) {
|
||||||
|
x = x - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do-until loop
|
||||||
|
|
||||||
|
let x: Int = 10;
|
||||||
|
do {
|
||||||
|
x = x - 1;
|
||||||
|
} until (x <= 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
Functions in Tact start with the fun keyword. Functions can receive multiple
|
||||||
|
input arguments and can optionally return a single output value. You can
|
||||||
|
return a struct if you want to return multiple values.
|
||||||
|
|
||||||
|
```js
|
||||||
|
fun average(a: Int, b: Int): Int {
|
||||||
|
return (a + b) / 2;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Maps and Arrays
|
||||||
|
|
||||||
|
### Maps
|
||||||
|
|
||||||
|
Maps are a dictionary type that can hold an arbitrary number of items,
|
||||||
|
each under a different key.
|
||||||
|
The keys in maps can either be an Int type or an Address type.
|
||||||
|
You can check if a key is found in the map by calling the get() method.
|
||||||
|
Replace the value under a key by calling the set() method.
|
||||||
|
|
||||||
|
```js
|
||||||
|
mi1: map<Int, TokenInfo>; // maps with Int as key
|
||||||
|
ma1: map<Address, TokenInfo>; // maps with Address as key
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arrays
|
||||||
|
|
||||||
|
To create an array, define a map with 'Int' type as key as well as value.
|
||||||
|
|
||||||
|
```js
|
||||||
|
arr: map<Int, Int>; // this is our array implemented with a map
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ownable Standard Library
|
||||||
|
|
||||||
|
The Ownable trait allows the contract to set an owner role, which can have
|
||||||
|
higher priviliges from everybody else.
|
||||||
|
For this you would need to import the "@stdlib/ownable" library and inherit
|
||||||
|
it in your contract
|
||||||
|
|
||||||
|
- Use the self.requireOwner() call to verify that the person making that
|
||||||
|
function call is the owner of contract
|
||||||
|
- 'ChangeOwner{newOwner: Address}' message which allows the owner to
|
||||||
|
transfer ownership.
|
||||||
|
- Define state variables named 'owner: Address' and 'stopped: Bool' and
|
||||||
|
call 'self.requireNotStopped()' on actions that should be stopped.
|
||||||
|
- Define state variables named 'owner: Address' and "stopped: Bool' and
|
||||||
|
call 'self.requireNotStopped()' on actions that should be stopped.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import "@stdlib/ownable";
|
||||||
|
import "@stdlib/deploy";
|
||||||
|
|
||||||
|
contract Counter with Deployable, Ownable {
|
||||||
|
owner: Address;
|
||||||
|
|
||||||
|
init() { // initialize a contract with default values like 'constructor'
|
||||||
|
self.owner = sender(); // we can initialize owner to any value we want, the deployer in this case
|
||||||
|
self.val = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this message in only available to the owner
|
||||||
|
receive("double") {
|
||||||
|
self.requireOwner();
|
||||||
|
self.val = self.val * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this message will only work until the contract was stopped
|
||||||
|
receive("increment") {
|
||||||
|
self.requireNotStopped();
|
||||||
|
self.val = self.val + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this message will only work as long as the contract is not stopped
|
||||||
|
receive("increment2") {
|
||||||
|
self.requireNotStopped();
|
||||||
|
self.val = self.val + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Additional resources
|
## Additional resources
|
||||||
|
|
||||||
- [TON Documentation](https://ton.org/docs/#/)
|
- [TON Documentation](https://ton.org/docs/#/)
|
||||||
- [Tact Docs](https://docs.tact-lang.org/)
|
- [Tact Docs](https://docs.tact-lang.org/)
|
||||||
|
- [Tact by Example](https://tact-by-example.org/)
|
||||||
- [Community portal](https://society.ton.org)
|
- [Community portal](https://society.ton.org)
|
||||||
- [Blockchain portal](https://ton.org)
|
- [Blockchain portal](https://ton.org)
|
||||||
- [Stackoverflow](https://stackoverflow.com/questions/tagged/ton)
|
- [Stackoverflow](https://stackoverflow.com/questions/tagged/ton)
|
||||||
|
|
||||||
## Social
|
## Social
|
||||||
|
|
||||||
- [Tact community](https://t.me/tactlang)
|
- [Tact community](https://t.me/tactlang)
|
||||||
- [Developer community](https://t.me/tondev_eng)
|
- [Developer community](https://t.me/tondev_eng)
|
||||||
- [TON Learn](https://t.me/ton_learn)
|
- [TON Learn](https://t.me/ton_learn)
|
||||||
- [Tondev News](https://t.me/tondevnews)
|
- [Tondev News](https://t.me/tondevnews)
|
||||||
|
- [TON Technical Updates](https://t.me/thetontech)
|
||||||
|
|
||||||
## Useful blogposts
|
## Useful blogposts
|
||||||
|
|
||||||
@ -244,7 +597,7 @@ contract Integers with Deployable {
|
|||||||
- Add smart contracts examples
|
- Add smart contracts examples
|
||||||
- Add more links to documentations
|
- Add more links to documentations
|
||||||
|
|
||||||
This file is based on [Tact By Example](https://tact-by-example.org/04-decimal-point).
|
This file is based on [Tact By Example](https://tact-by-example.org).
|
||||||
|
|
||||||
P.S. If by any chance you're familiar with [Forth](https://learnxinyminutes.com/docs/forth/),
|
P.S. If by any chance you're familiar with [Forth](https://learnxinyminutes.com/docs/forth/),
|
||||||
you can also take a look at [Fift](https://ton-blockchain.github.io/docs/fiftbase.pdf).
|
you can also take a look at [Fift](https://ton-blockchain.github.io/docs/fiftbase.pdf).
|
||||||
|
Loading…
Reference in New Issue
Block a user