Skip to content
This repository was archived by the owner on Oct 28, 2026. It is now read-only.
rainydioPublic archive

About

Security review of TON smart-contract contest entries, commissioned by Telegram (2019)

Resources

Stars

0 stars

Watchers

2 watching

Forks

Repository files navigation

TON Smart Contract Contest — Security Review (2019)

In autumn 2019 Telegram ran a series of open contests on contest.com to build smart contracts for the Telegram Open Network (TON) blockchain, written in FunC.

After competing in the contest myself, I was commissioned by Telegram to review the submissions of the second round ("blockchain-2") and report issues to the judging panel. This repository is that review.

Scope: 26 submissions reviewed, with 22 covered in dedicated folders (entryNNNN) and the rest in inline comments.

Typical findings:

  • contracts whose funds could be drained by an attacker
  • front-running of user operations
  • undersized sequence numbers that allow wrap-around and replay
  • suppressed message-send errors that silently lock user funds
  • processing fees not accounted for, or paid from the contract's own balance
  • flawed code copied from reference contracts

The sections below cover issues common to many entries, followed by per-entry reviews. Review depth varies (see the legend in Reviews): it was a time-boxed engagement, so some entries got a full audit and others a shallow pass.

Contestant names on contest.com were anonymous nicknames (e.g. "Mellow Squid"); I keep them here as they appeared on the portal.

Returning change from processing fee

Many contract that accept deposits do not account processing fees. Usually whole msg_value is added to deposit. Mellow Squid uses simple technique to return change from processing fee:

raw_reserve(get_balance().first() - processing_grams_max, 0);
send_message_back(s_addr, 0xf374484c, 0, 0, 0, 128);

Shiny Giraffe also uses exact same technique:

raw_reserve(get_balance().first() - msg_value + deposit, 0);
send_message_back(s_addr, 0xf374484c, 0, 0, 0, 128);

Suppressing send_raw_message errors

Generally any send_raw_message +2 usage indicates that contract balance is lower than expected. Otherwise why there is error at all? At some point during processing withdrawal ignoring the error will lock someone's funds. As result real balance will become higher than expected, and contract will continue operating normally repeating the cycle.

It will look like random glitch and those who are unlucky will complain on the internet.

Contract paying for processing

Many contracts contain accept_message, set_gas_limit, or buy_gas calls within internal message handler. It's often combined with send_raw_message +2 because gas consumed creates severe discrepancy between real and expected balance. Due to fatal misfortune or deliberate act of sabotage, processing withdrawal may leave contract with small yet still positive balance. It will run out of funds during next accept_message.

I haven't reviewed standard contracts yet, but Slim Dodo copied erroneous code from elector-code.fc

Reviews

Most submission pages contain aggregate claims that were combined by me. So please verify them if uncertain. Progress notation in the list below:

  • no review
  • shallow review
  • incomplete review
  • almost complete review
  • complete review

Not in the list, will add them later except:

  • Classy Bee. It's good, we all know that.
  • Eager Boar. It's meh. Reviewed it in comments.
  • Hip Hyena. So many errors. Reviewed it in comments.
  • Bold Wolf. It's terrible. Reviewd it in comments.

In the list, but need some additional work:

  • Big Elk. Appears to be simplest client-server C++ app.
  • Mad Crow. So many errors. Difficult to untangle.

Submissions

About

Security review of TON smart-contract contest entries, commissioned by Telegram (2019)

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors