Build a poll dApp on TON
A hands-on tutorial: from zero to a live, on-chain poll with a React frontend.
The "hello world" of smart contracts on most blockchains is a counter contract. Yet, this contract is not sufficient for overcoming two main struggles of contracts on TON: asynchronicity and account limits, especially data and computation limits. The former prevents contracts from directly impacting the state of each over during computation, only allowing asynchronous message exchange.
As for the latter, one cannot place a large hashmap for individual user data in a single contract and expect it to scale. A single contract cannot hold too much data, and cannot perform too much computations in a single transaction initiated by an incoming message. Instead of trying to use a large hashmap, the common approach is to shard the contract by making the parent contract an entry point and a manager of its subsidiary child contracts, where each child contract holds and modifies individual user data.
The poll smart contract built and deployed during this tutorial would address both concerns and help wrap the head around TON specifics. It will not present the right solution right away: there will be two intentional dead ends on the way to the final architecture to make the concepts stick.
What this tutorial builds
A poll smart contract that:
- Accepts binary votes (Option A / Option B) from any TON wallet
- Prevents the same wallet from voting twice
- Can be closed by its owner, returning remaining funds
- Exposes live vote counts via a getter
One can think of this poll contract as a decentralized but oversimplified version of the Telegram built-in polls.
Concepts covered
- Tolk: the smart contract language for TON
- Asynchronicity and multi-contract, sharding architecture: deploying and managing the child contracts from a parent
- Bounced messages as feedback and rollback mechanism
- Acton: the all-in-one TON smart contract development toolkit
- Project setup:
acton new,acton build,acton check,acton fmt - Tests:
acton testwith--ui,--coverage,--mutate, and--snapshot - Autogenerated test and script helpers:
acton wrapper - Deployments:
acton wallet,acton script --net testnet,acton verify,acton retrace - Adding a dApp frontend with TON Connect UI on a Vite + React scaffold
- Project setup:
Prerequisites
- Acton: run
acton up --stableor follow Installation. - Node.js 22 or later: needed only for the last step when adding web frontend to the project.
- Funded testnet wallet: needed only for the semi-last step when deploying to testnet; created during the tutorial.
Pages
1. Create your first project
Scaffold the project, explore the structure, and run the first build.
2. First attempt: one contract
Sketch the obvious approach and discover why it breaks at scale.
3. Sharding: Poll + Voter
Split into two contracts and learn how a parent deploys child contracts.
4. Test the multi-contract flow
Write integration tests and use the Test UI to visualize message traces.
5. Turn a bounce into a callback
Use bounced messages to prevent double-counting.
6. Mutation and fuzz testing
Harden tests with mutation testing and fuzz inputs.
7. Close the poll
Add owner access control, close logic, and a gas snapshot baseline.
8. Deploy to testnet
Go live on testnet, verify the source, and retrace transactions.
9. Build the React frontend
Scaffold a Vite + React dApp with TON Connect UI and see live results in a browser.
Last updated on