# FunС
### Общая инфа
На текущий момент нет официальной документации по языку. FunC позволяет на более высоком уровне чем Fift создать смарт-контракт, используя такие примитивы как функции
### Пример из доки
```
;; Heavy-duty wallet for mass transfers (e.g., for cryptocurrency exchanges)
;; accepts orders for up to 254 internal messages (transfers) in one external message
() recv_internal(slice in_msg) impure {
;; do nothing for internal messages
}
() recv_external(slice in_msg) impure {
var signature = in_msg~load_bits(512);
var cs = in_msg;
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
throw_if(35, valid_until <= now());
var ds = get_data().begin_parse();
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
ds.end_parse();
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, subwallet_id == stored_subwallet);
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
var dict = cs~load_dict();
cs.end_parse();
accept_message();
int i = -1;
do {
(i, var cs, var f) = dict.idict_get_next?(16, i);
if (f) {
var mode = cs~load_uint(8);
send_raw_message(cs~load_ref(), mode);
}
} until (~ f);
set_data(begin_cell()
.store_uint(stored_seqno + 1, 32)
.store_uint(stored_subwallet, 32)
.store_uint(public_key, 256)
.end_cell());
}
;; Get methods
int seqno() method_id {
return get_data().begin_parse().preload_uint(32);
}
```
## Построчно разберем код
Первая функция:
```
() recv_internal(slice in_msg) impure {
;; do nothing for internal messages
}
```
Она принимает внутреннее (internal) сообщение от контракта в сети TON. Нужна для коммункации между контрактами.
```
Указывает на то, что функция ничего не возвращает void
|
| Принимает slice объект от другого контракта
| |
| | Декоратор, видимо говорящий о том, что функция не явлеятся getter, деталей пока нет
V V V
() recv_internal(slice in_msg) impure {
}
```
Фактически функция игнорирует любой запрос со стороны контракта, а не пользователя. Пользователь делает external сообщения в сеть. Оба типа сообщений даже у нод по-разному хранятся.
Важно понимать, что slice тут, по факту просто куча байтов произвольной длины
____
```
() recv_external(slice in_msg) impure {
```
Имеет такую же логику как и internal, отличается лишь неймингом, который очень ВАЖЕН!
```
var signature = in_msg~load_bits(512);
```
Обозначем переменную signature, которая грузится из первых 512 бит slice переменной in_msg, которую нам передали
По guidelines от создателей они решили разбить на участки slice in_msg
Первый участок - подпись 512 бит
```
a~load_bits(b);
```
load_bits возвращает первые (мб и нет) b бит из slice переменной a
```
var cs = in_msg;
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
```
Тут сначала непонятно зачем создается cs переменная из in_msg, это может быть связано с тем, что in_msg и cs находятся в разных областях памяти и cs переменная на чтение будет требовать меньше или 0 газа в отличии от in_msg (а может и нет, просто по фану сделали)
```
var (subwallet_id, valid_until, msg_seqno) = (cs~load_uint(32), cs~load_uint(32), cs~load_uint(32));
```
Массовое создание и присвоение значений
var (a, b, c ... , d) = (z, y, x, ... , f)
Тут опять загружается 32 бита из slice переменной
Видимо после заргрузки N бит, переменная slice уменьшается на эти N бит
Собственно создаются переменные:
subwallet_id - некий id кошелька
valid_until - момент, до какого числа сообщение external будет действительным. Иначе злоумышленник может похитить ваше сообщение из пула всех сообщений и выполнить его в любое время
msg_seqno - так называемый nonce. Некое число, которое отображает количество уже подписанных и отправленных тобой транзакций. Если его не будет, то злоумышленник может украсть твою подпись, сумму, автора и повторять заносить эти данные как новые транзакции
```
throw_if(35, valid_until <= now());
```
throw_if выбрасывает ошибку с кодом 35, если условие valid_until <= now() не выполняется
now() - позволяет получить текущее время
Проверка нужна на то, что не просрачилась транзакция
```
var ds = get_data().begin_parse();
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
ds.end_parse();
```
get_data() - метод для того, чтобы начать считывать данные из клеток (я так понимаю, что за контрактом закреплен некий storage, то, как из него читать и писать примерно известно)
get_data() - открывает некий поток, а ля io.open / close
get_data().begin_parse() - позволяет из него читать
```
var (stored_seqno, stored_subwallet, public_key) = (ds~load_uint(32), ds~load_uint(32), ds~load_uint(256));
```
Тут мы получем уже сохранненные данные из клетки в memory переменные
stored_seqno, stored_subwallet, public_key - очевидно, что это такое
```
throw_unless(33, msg_seqno == stored_seqno);
throw_unless(34, subwallet_id == stored_subwallet);
throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key));
```
проверяем, что nonce сходится, иначе кидаем ошибку с кодом 33
проверяем, что subwallet_id сходится, иначе кидаем ошибку с кодом 34
проверяем, что подпись сходится с публичным ключом владельца, иначе кидаем ошибку с кодом 35
```
check_signature(slice_hash(in_msg), signature, public_key)
```
Функция проверки подписи, где нужно передать подпись, публичный ключ и hash от сообщения отправителя
```
var dict = cs~load_dict();
cs.end_parse();
```
Идет загрузка dictionary объекта (hashmap видимо). У него есть отдельный метод для загрузки. Видимо в памяти он аллоцирован иначе чем slice данные и читается оттуда как из потока