A vanity address for your Telegram Wallet (Money): UQ…_Gram, UQDurov…, any short text.
The search runs on your computer or your own GPU server. You get 24 words and import them into Telegram. Only you know the key.
- Search. Find 12 BIP39 words (1–12) whose address contains your text. Each character makes the search ~64× longer.
- Your key. Words 13–24 come from the OS random generator. They never leave your computer.
- Key change. Your wallet (TON Connect) sends one message: 0.01 GRAM + deploy + key change. After it, words 1–12 control nothing.
- Import the 24 words into Telegram.
Only the public key of words 13–24 and one signature go to the network.
Telegram keeps one wallet.
- Settings → Money («Настройки → Деньги»).
- Move coins out of the old wallet, or save its phrase. Delete it.
- Import the 24 words in order.
- Check that the address ends with your text.
Needs Rust 1.85+.
git clone https://github.com/catchain/gram-vanity
cd gram-vanity
cargo run --releaseThe program opens http://127.0.0.1:PORT/#t=… in your browser.
Manifest. The wallet downloads ui/tonconnect-manifest.json from this repo. Nothing to set up. For your own: --manifest-url https://….
Settings. Copy .env.example to .env. Environment variables win.
| Key | Meaning |
|---|---|
TONCENTER_API_KEY |
Optional. Without it: 1 request/s, enough. With it: 10/s. |
VANITY_MANIFEST_URL |
Optional. Same as --manifest-url. |
Terminal only:
cargo run --release -- mine --suffix _Gram # CPU search, prints words 1–12
cargo run --release -- bench # CPU speed| Hardware | Rate | 6 chars, exact case |
|---|---|---|
| Apple M2, 8 threads | ~15,000/s | ~55 days |
| 4× RTX 5090 (measured) | ~6,000,000/s | ~3 hours |
Any case is much faster. For 6+ characters use the GPU: worker/README.md. The GPU tab starts it over SSH.
- Key stays local. Words 13–24 live only in memory. No disk, no core dumps.
- GPU server sees only words 1–12. Until the key change, its owner could take the address (not funds). Change the key right after the search.
- Atomic. Top-up, deploy and key change are one message. No funds sit under words 1–12.
- Two origins. The words page (
/) has a strict CSP and no external requests. TON Connect runs on a second port and cannot read it. - Local only. Listens on
127.0.0.1. Token +Host+Originchecks (CSRF, DNS rebinding). - Read-only network. Only public account state from toncenter.
- Self-test at start: code hash, Acton vector, a real mainnet address.
- Foreign key check. Refuses to build a key change if the on-chain key is somebody else's.
- «Стереть» zeroizes word buffers (not HTTP buffer copies). The clipboard clears 60 s after a copy. Write the words on paper.
If the key change fails (the request is valid 4 minutes), the address is still deployed with the key of words 1–12. The page shows «развёрнут, ключ ещё не ваш». Send again: the program rebuilds it without deploy, with the current seqno.
- Contract: tg-wallet-contract, subwallet
0x7FFF7F11. - Address:
hash(StateInit{trampoline, [rev 0][seqno 0][0x7FFF7F11][pubkey of words 1–12]}). - Keys: BIP39 seed (PBKDF2-HMAC-SHA512, 2048 rounds), SLIP-0010 ed25519
m/44'/607'/0'. - Key change:
ChangePublicKeyRequestI(op0xFBBA99C7) signed by words 1–12, with aKEY_ROTATIONproof signed by words 13–24. - Reference: Acton (
MnemonicScheme::Rotation). Output matches vanity.tg byte for byte.
cargo test --release # reference vectors, fast PBKDF2
(cd tests/js && npm install && npm test) # e2e in @ton/sandbox, live mainnet config
(cd worker && make test) # GPU core vs Rust, emulated, no GPU neededThe sandbox test checks the key change, seqno, replay and old-key rejection, expiry and the recovery path. Not automated: a real mainnet transaction, the Telegram import, the CUDA build.
Issues and PRs are welcome. Run the tests first. Security problems: SECURITY.md.
MIT. Third-party code keeps its license:
| Path | Source | License |
|---|---|---|
ui/vendor/tonconnect-ui.min.js |
@tonconnect/ui 3.0.2 | Apache-2.0 |
worker/ed25519/ |
orlp/ed25519, modified for CUDA | zlib |
ui/fonts/ |
Onest, JetBrains Mono | SIL OFL 1.1 |