Simulating a bank with a smart contract on TON blockchain. Part II
Tags: blockchain, ton, smartcontract, func
Published: 2023-06-02 19:03:17


![surprise smart contract](https://res.cloudinary.com/djjd0wi5i/image/upload/v1685729946/photo_2023-06-02_20-18-17_uewm3r.jpg)

In my [previous post](https://gealber.com/bank-smart-contract-ton-part-i) I described that I wanted to implement a smart contract that would simulate the basic functionalities of a bank. For a full description of those operations, I strongly recommend you to take a look at the [Part I](https://gealber.com/bank-smart-contract-ton-part-i) of these posts. 

As I promise, I'll give now in this post, a basic overview of the code. This helped me a lot in knowing how [FunC](https://docs.ton.org/develop/func/overview) works, and common pitfalls that you will encounter if you don't take clear caution. I'll describe two of them. It took me a lot of time to figure out the reason, and the reason was so simple as the absence of an [impure specifier](https://docs.ton.org/develop/func/functions#impure-specifier). This error gives me a lot of headache, but let's go to the description and analysis of the code.

## Requirements

The repository containing this code can be found in [Gealber/blog_recipes/bank_contract](https://github.com/Gealber/blog_recipes/tree/main/bank_contract). My only intention with this post is to analyze the code, so there won't be any requirements. Nevertheless, it is important to know how to set up your env to run code from someone else. If you are just starting with TON, I recommend you to take a look at the [Hello World tutorial](https://ton-community.github.io/tutorials/02-contract/). This tutorial will give you a better understanding on what is needed, and in general it's a better tutorial overall. In case you are wondering what you will need to deploy this smart contract in specific, I recommend you to take a look at these files in the [repository](https://github.com/Gealber/blog_recipes.git):

1. [deploy.sh](https://github.com/Gealber/blog_recipes/blob/main/bank_contract/deploy.sh)
2. [scripts/compile.sh](https://github.com/Gealber/blog_recipes/blob/main/bank_contract/scripts/compile.sh)
3. [main.go](https://github.com/Gealber/blog_recipes/blob/main/bank_contract/main.go)

## Structure
As always it is quite useful to have an understanding of the project structure in order to be able to read someone else's code. My advice is always to look for the main thread, that in our case, given that it's a smart contract, our main thread will be that method that handles inbound messages. In the TON blockchain this method is called [recv_internal](https://docs.ton.org/develop/func/functions#receive-internal). Making a simple

`grep recv_internal -rn --include=*.fc`

You should receive the following output:

`contracts/bank.fc:1:() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure`

Which tells us that this method is located in contracts/bank.fc line 1, so let's start with this file. In cases where the content of a method is too large I'll avoid displaying all its content here, you can always check it out in the [source code](https://github.com/Gealber/blog_recipes/tree/main/bank_contract).

**file: bank_contract/bank.fc**

```c
() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure {
    ;; start parsing the cell
    var cs = in_msg_cell.begin_parse();
    ;; load the following flags: int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
    var flags = cs~load_uint(4);
    ;; load sender address
    slice s_addr = cs~load_msg_addr(); 

    if (slice_empty?(in_msg)) {
        return ();
    }


    ;; parsing address and checking its workchain
    var address = parse_work_addr(s_addr);    
    process_client_request(address, flags, msg_value, in_msg);
}

```

**recv_internal definition**

`() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure`

If you take a look, **recv_internal** will be able to receive 3 arguments:

1. The first one is the **msg_value** that is not other than the amount of TONS that were sent on the message.
2. **in_msg_cell** contains the inbound message as a cell.
3. **in_msg** contains the body of this inbound message as a [slice](https://docs.ton.org/develop/func/types#atomic-types).

There's another word in the definition that is quite important, which is the [impure specifier](https://docs.ton.org/develop/func/functions#impure-specifier).

The method starts parsing a [Cell](https://docs.ton.org/develop/data-formats/cell-boc#cell), which is the main structure in the TON blockchain where data is stored. Honestly I don't have a full grasp yet on how Cells are serialized and so on, and I don't think that is necessary to start tinkering with them. Keep in mind that we store up to **1023** bits on them, and can have **4** references to other cells. In case we will need to store more than **1023** bits, you create another cell, and reference the previous one to this new one. Again this is not needed now.

```c
    ;; previous code

    ;; start parsing the cell
    var cs = in_msg_cell.begin_parse();
    ;; load the following flags: int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
    var flags = cs~load_uint(4);
    ;; load sender address
    slice s_addr = cs~load_msg_addr();
```

In this block of code we parse the cell, to extract the **flags and the sender address**. The **flags** will tell us later if this message is not a result of a bounce.Next we have a call to 

`process_client_request(address, flags, msg_value, in_msg);`

we need to figure out what this does. Making a simple search like in the other time you can notice that **process_client_request** is defined in the [requests.fc](https://github.com/Gealber/blog_recipes/blob/main/bank_contract/contracts/requests.fc) file. This method will handle the operation codes, send in the message body(in_msg), and dispatch **handle_deposit**, **handle_withdraw**, and **handle_borrow** accordingly. Take a look at the following snippet:

```c
    int op = in_msg~load_uint(32);
    if (op == op::deposit()) {
        ;; handle deposit of funds by the user        
        handle_deposit(address, msg_value);
    }

    if (op == op::borrow()) {
        ;; handle borrow of money by the user
        ;; fixed amount to borrow, 1% of the current balance
        handle_borrow(address);        
    }

    if (op == op::withdraw()) {
        ;; handle withdraw of user funds
        handle_withdraw(address, in_msg);
    }

```

Until now we have the following flow

![flow](https://res.cloudinary.com/djjd0wi5i/image/upload/v1685730231/photo_2023-06-02_20-23-38_yf05j0.jpg)

With this general idea of the structure of the code, you now can deep dive into the code. Important to notice that smart contracts in TON are a thing, as it is described in the [documentation](https://docs.ton.org/learn/overviews/ton-blockchain#single-actor), they have address, data, balance, etc...basically an object. Each event is handled one by one, following the [Actor pattern](https://en.wikipedia.org/wiki/Actor_model).


## Common pitfalls

**TVM Exit Code 7**

If you take a look at the repository, you can notice the presence of a file called **errors.history.txt**. This file contains two of the errors that I encountered while developing this smart contract, there were more but I think these two were the more hard to debug. One of them I still don't know why happens, obviously this is due to lack of knowledge on my part. 

The one that was really a pain in the ass, was the one related to **TVM Exit Code 7**, now this error according to the [doc](https://docs.ton.org/learn/tvm-instructions/tvm-exit-codes). 

_Type check error. An argument to a primitive is of an incorrect value type._


In my case this was happening in a line where I was modifying a global variable, which wasn't initialized by the [load()](https://github.com/Gealber/blog_recipes/blob/061ad35411bf30a9d8243f34d7c0e8b37f2fd8f3/bank_contract/contracts/storage.fc#L12) method. The problem was that I didn't specify the [impure specifier](https://docs.ton.org/develop/func/functions#impure-specifier) at the end of this method definition, neither in [store_base_data()](https://github.com/Gealber/blog_recipes/blob/061ad35411bf30a9d8243f34d7c0e8b37f2fd8f3/bank_contract/contracts/storage.fc#L26). As long as the method modifies the contract storage, like in these cases, you should put this specifier. There are other cases as well that I strongly recommend you to check in the [documentation](https://docs.ton.org/develop/func/functions#impure-specifier).

**Develop without testing**

In **personal projects** we as lazy people try to undermine the importance of testing, and we always leave it to the end, or don't do it at all. The issue is that developing a smart contract without testing it properly, from the beginning to the end, costs you **money**. My personal advice, try to set up your testing environment and make use of the [ton-contract-executor](https://github.com/ton-community/ton-contract-executor). Extremely useful, this project, awesome. You can also check out [blueprint](https://github.com/ton-community/blueprint), which I haven't used, but it's recommended by the official documentation.

## Advice


**Don't get scared of TVM Assembly**

Many times you will encounter definitions in the [Standard Library](https://docs.ton.org/develop/func/stdlib/), written in [TVM Assembly](https://docs.ton.org/develop/fift/fift-and-tvm-assembly). Also in the logging of **ton-contract-executor** what you will get will be Assembly as well. Don't be scared.



## Conclusion

In general I think it was quite a good experiment, it's not a perfect code, not a perfect idea either, quite hackable actually. I learned a lot. I strongly recommend that if you want to learn something, go and try to build something on it, even if it's quite a silly idea.