Before we start writing our token and then the smart contract system, let’s take a quick look at the important elements of smart contracts for Free TON.
In the previous article Hello World Smart Contract For Free TON, we looked at the very beginning of working with Free TON and HelloWorld smart contracts.
The structure of this article:
- Int and uint numeric types, pure functions, and event: writing a calculator on the blockchain;
- Structures and arrays: smart contracts as a database;
- Hash tables: mapping;
- Public keys and require.
You can declare a variable with a numeric type using int (signed integer) and uint (unsigned integer). You can write the number of bits for the number in the suffix of the specified numeric type, for example: int8, int16, uint128. The int and uint types are the same as int256 and uint256. We perform arithmetic operations on numbers in a smart contract.
Now let’s write a smart contract with a calculator. It has a single calc function that accepts 3 uint parameters: 2 operand numbers and a number indicating the number of operations on the operands passed to the function. Our calc function has a pure modifier, which means that this function does not use smart contract data, but performs its operations only with what is passed to it in the arguments.
In the case when an unknown operation number is passed to a function, we generate an event that informs the external application that calls our smart contract that something has happened.
Event is used very often in smart contracts, it came in handy for us in order to inform additional information that the result 0 returned by the function is not a result, but an error related to the fact that an unknown number of an arithmetic operator was passed.
Structures And Arrays
What we declare at the beginning (usually) of a smart contract, outside of the function area, refers to the memory area associated with the smart contract. And since the smart contract is eventually uploaded to the blockchain, the data of the smart contract is stored in the blockchain as in a database. Let’s write a simple smart contract for storing data in the blockchain.
User structure in our contract is used to store information about the user, and contains 2 data fields of the uint type: user weight and balance. Since we want to store data not about one, but about many users, after declaring the structure, we declared an array of structures of this type. Now we can add users to our array using push, and then after calculating the new user ID by the array index — we return it in the NewUser event.
Pay attention to how the return of values by the GetUser function looks like: in this case, we declare variables in returns, to which we assign values in the body of the function. Note that we changed the pure modifier to view.
Hash Tables: Mapping
Above, we looked at arrays where the key to the value (User) is the index (or ordinal number, starting from zero) of the element in them. Another type of collecting elements is mapping. We can store sequences of elements of a given type in them, as in the case of arrays, but unlike arrays, the keys to such values are not simple numeric indexes, but values of another given type. This allows you to search for elements in the reflection by string, address, public key, and other values.
Let’s add this mapping to our slightly redesigned example:
Public Keys And Require
Calling a smart contract function is similar to sending a message, we send an object containing the name of the called function and parameters for it (if they are required) to the address of the account with the smart contract. Also, additional data can be included in the message: public key, signature, value for transferring TON Crystal tokens to the called account. Let’s talk about the public key.
You can get the value of the public key of the account that sent the message to our smart contract by calling the msg.pubkey() API function. In the NewToken() function, we assigned accounts[tokens.length-1] = msg.pubkey(); in which for each newly created token ID, the public key of the account that created this token is placed in the accounts mapping, and as a key we use the identifier of this token, which is calculated after the tokens array is added. Then, in SetTokenInfo(), where we can configure the name and symbol for our token, we set a requirement, only after which it is possible to continue calling the function. We take the sender’s public key by the tid value, find the public key set during creation in the accounts mapping, and compare them. Only if they are equal we will be able to set or change the name and symbol of the token.