A lottery you can enter without leaving Telegram and without owning a wallet first.
Players deposit into a shared pool from a Telegram Mini App. When the pool reaches its limit, the contract picks winners, pays them, takes the organiser's cut and resets. The draw, the payout and the reset all happen on-chain, so the result is checkable by anyone rather than announced by the organiser.
The interesting constraint was onboarding. A lottery only works if entering it is easier than not entering it, and asking a Telegram user to install a wallet extension, fund it and sign a transaction loses almost everyone at step one. So the wallet is created behind the login, and the transaction is sponsored.
| Contract surface | What it does |
|---|---|
deposit |
Player enters the pool. Contribution recorded against their address. |
poolBalance / totalPoolLimit |
Current pot, and the ceiling that triggers a draw. |
participants / totalParticipants |
The entrant set for the current round. |
selectWinners |
Picks the winners for the round. |
payoutWinners |
Pays them out. Emits WinnersPaid. |
organizerFeePercentage |
The organiser's cut, fixed in the contract rather than applied off-chain. |
getEthPrice / getEthAmountInUsd |
Converts entries and prizes to USD for display. |
PoolReset |
Emitted when the round closes and the next one opens. |
Events: Deposit, WinnersPaid, PoolReset. Every round is reconstructable from logs.
Three pieces do the work:
- Embedded wallets. Privy and Magic create a wallet from an email OTP, a Google login or a passkey. No extension, no seed phrase at signup.
- Account abstraction. ZeroDev and
permissionlessput the account behind ERC-4337, so entering a draw is a user operation rather than a raw transaction the player has to fund first. - Telegram as the surface.
@twa-dev/sdkruns the whole thing as a Mini App, inside the chat where the players already are.
| Framework | React 18, Vite, TypeScript |
| Wallets | Privy, Magic (email OTP, Google OAuth, WebAuthn) |
| Account abstraction | ZeroDev SDK, permissionless |
| Surface | Telegram Mini Apps (@twa-dev/sdk) |
| UI | Tailwind CSS, Radix UI, Framer Motion |
| Charts | lightweight-charts |
| Chat | Subsocial Grill widget |
| Network in code | Ethereum Sepolia |
npm install
npm run dev # dev server
npm run build # production build
npm run lintTelegram Mini Apps must be served over HTTPS, which is why @vitejs/plugin-basic-ssl is
in the dev dependencies. Point a Telegram bot at the dev URL to test inside the client
rather than in a browser tab.
src/
abis/ contract ABIs
components/ UI, including the Magic and Privy auth flows
hooks/ contract reads and writes
pages/ app screens
data/ static config
lib/ helpers
abi.json the pool contract interface
Built as a hackathon project. The contract interface, the Telegram surface and the account-abstraction path all work end to end. It is a demonstration of the onboarding idea, not an audited production lottery, and should not be treated as one.