TON Stablecoin

CertiKCode version: not recorded (see the report)

CertiK reviewed TON (TON Stablecoin) on 7 Dec 2022: 9 findings, 0 critical; 8 marked fixed, 1 open.

No open critical findings
Open the reportOpen TON’s security record

Report hosted on skynet.certik.com.

Trustblock does not review code.

Findings9

Statuses are the security firm’s own, from its report.

SeverityOpenAcknowledgedFixed
Critical000
High100
Medium003
Low005
Medium`workchain` is not enforced in `op::mint`Fixed

`jetton-minter` during processing of `op::mint` message uses `calculate_user_jetton_wallet_address()` to prepare the `jetton-wallet` address. However, even if `to_address` is not in basechain, the generated wallet address is in `workchain = 0`. As a result, the minted jettons will not be accessible.

MediumBounced `op::internal_transfer` message from `jetFixed

When `op::internal_transfer` message is bounced from one `jetton-wallet` to another one, the `balance` is updated (increased back). However, if `op::internal_transfer` message is bounced from `jetton-wallet` to `jetton-minter`, the `total_supply` is not updated. `master_msg` provided to `op::mint` is not validated and passed as is to `jetton-wallet`. Underflow can happen. As a result the total circulating supply will be less than `total_supply`.

MediumLack of arguments validation in `jetton-minter`Fixed

During processing of `op::upgrade` the inconsistent `new_data` can be assigned. That will invalidate all the deployed wallets or `total_supply` value. `new_code` is not validated for correctness. Inconsistent storage can be also set during `jetton-minter` deployment. During processing of `op::call_to` and `op::mint` the `master_msg` and `amount` are not validated. During processing of `op::change_content` it is not validated that updated `content` follows [TIP-64 (Token Data Standard)](https://github.com/ton-blockchain/TIPs/issues/64). Incorrect data can be assigned. `symbol`, `name`, `decimals` can be changed. Well known Jetton can be renamed to something else or to another well known Jetton. This can influence the Jetton price. During processing of `op::change_admin` the `new_admin_address` is not validated. Assigning the wrong admin can prevent further minting.

Low`end_parse()` Is MissingFixed

The function `load_data()` reads all the fields of Storage, however, it does not ensure that the slice is empty after that.

Low`status` is not documentedFixed

According to the code zero `status` is considered "unlocked". Any other `status` is considered "locked". Locked status forbids performing `send_tokens()` but allows to `burn_tokens()` and `receive_tokens()`.

LowCode documentation can be improvedFixed

In `calculate_jetton_wallet_state_init()` `StateInit` structure is used: ```c _ split_depth:(Maybe (## 5)) special:(Maybe TickTock) code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) = StateInit; ``` In `calculate_jetton_wallet_address()` `MsgAddressInt` structure is used: ```c addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256 = MsgAddressInt; ``` `send_raw_message()` arguments preparation is not documented. `send_raw_message()` `mode` argument is not documented in comments. No corresponding constants introduced.

LowInaccurate commentsFixed

`Storage` comment in `jetton-wallet` doesn't mention `status` field. `transfer` and `internal_transfer` comments don't contain the structure tags. Other structures: `transfer_notification`, `excesses`, `burn`, `burn_notification`, - should be described. `founds` is supposed to be `funds`. `steel` is supposed to be `still`. `uin4` is supposed to be `uint4`. `is only decreases` is supposed to be `only decreases`.

LowTIP-74 standard is not followed regarding `op::exFixed

According to [TIP-74 standard (TON fungible tokens)](https://github.com/ton-blockchain/TIPs/issues/74) "After processing the request, the receiver's jetton-wallet **must** send at least `in_msg_value - forward_amount - 2 * max_tx_gas_price` to the `response_destination` address. If the sender jetton-wallet cannot guarantee this, it must immediately stop executing the request and throw error." So, the `op::transfer` is allowed to do two processings only. However, these values can be deducted: 1. Up to `min_tons_for_storage` can be left on the `receiver_wallet` 2. Up to 2 forward fees can be spent: one for `op::internal_transfer` from `sender_wallet` to `receiver_wallet`, one for `op::transfer_notification` from `receiver_wallet` to `receiver_owner` 3. 2 processing fees can be spent: one for `op::transfer` processing, one for `op::internal_transfer` processing In fact `op::excesses` message will get only `op::transfer::in_msg_value - forward_ton_amount - min_tons_for_storage - 2 * fwd_fee - 2 * max_tx_gas_price`. Also, `gas_consumption` constant is hardcoded, not obtained from `ConfigParam21 gas_limit`. This makes the calculations inaccurate for different workchains.

Contracts in scope

No deployed address is recorded for this audit.

The report names a repository or files. Open the report to see its scope.

Part of TON’s security record

TON
Audits6 audits by 2 firmsLast audit Mar 2024, by Trail of Bits.
Critical findingsNo open critical findingsAcross 6 reports.
Open TON’s security record

Security firm

CertiK

1,045 projects reviewed · 1,376 reports · latest May 2025

See CertiK’s audits

Something wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.

Tell us