Skip to content

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pcmehrdad committed Oct 1, 2024
1 parent f6c62b5 commit 16cf72c
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 2 deletions.
79 changes: 77 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,77 @@
# tongen
Ton Wallet v5 vanity address
# TON Wallet Address Finder

generate custom TON wallet addresses (V5) that end with a specific suffix.

## Features
- **Multi-threaded**: Utilizes multiple CPU cores to generate wallets in parallel.
- **Custom suffix**: Check if wallet addresses end with a specific string (case-sensitive or case-insensitive).
- **Supports Mainnet/Testnet**: Select the network where the wallets are generated.
- **Bounceable/non-bounceable**: Option to generate bounceable or non-bounceable addresses.
- **Real-time logging**: Logs the number of addresses processed every second.

## Installation

1. Ensure you have [Go installed](https://go.dev/doc/install).
2. Clone the repository and navigate to the project directory.
```bash
git clone https://github.com/ariadata/tongen.git
cd tongen
```

3. Build the project using the following command:

```bash
# Linux
CGO_ENABLED=0 go build -o tongen main.go
# Windows
go build -o tongen.exe main.go
```
You should now have an executable named tongen in your project directory.
### Download Pre-built Binaries [Click Here](https://github.com/ariadata/tongen/releases)
```bash
# Linux
curl -sSfL https://raw.githubusercontent.com/ariadata/tongen/main/build/tongen -o tongen && chmod +x tongen
# Windows
curl -sSfL https://raw.githubusercontent.com/ariadata/tongen/main/build/tongen.exe -o tongen.exe
```
### Usage

> `-suffix` (required): The desired suffix that the wallet address should end with.

> `-case-sensitive` (optional): Enable case-sensitive suffix matching. Defaults to false.

> `-bounce` (optional): Enable bounceable addresses. Defaults to false.

> `-threads` (optional): Number of parallel threads. Defaults to 0 (use all CPU cores).

> `-testnet` (optional): Use the testnet instead of the mainnet. Defaults to false.

## Examples:
```bash
# Generate a wallet non-bouncable address that ends with "_Neo" (case-sensitive) using all CPU cores on the mainnet
./tongen -suffix="_Neo" -case-sensitive=true -bounce=false -threads=0 -testnet=false
# Generate a wallet bouncable address that ends with "_Test" (not case-insensitive) using 4 threads on testnet
./tongen -suffix="_Test" -case-sensitive=false -bounce=true -threads=4 -testnet=false
```

### Example Output:
```bash
2024/10/01 20:00:01 Using 8 threads
2024/10/01 20:00:02 Processed 65 addresses in the last second
2024/10/01 20:00:03 Processed 68 addresses in the last second
=== FOUND ===
Seed phrase: "apple banana cherry date elephant ..."
Wallet address: UQDxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

-----

## Contributing
Feel free to submit issues, fork the repository, and make contributions. Pull requests are welcome!

License
This project is licensed under the MIT License.
Binary file added build/tongen
Binary file not shown.
Binary file added build/tongen.exe
Binary file not shown.
12 changes: 12 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module github.com/ariadata/tongen

go 1.22.5

require github.com/xssnick/tonutils-go v1.9.9

require (
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sys v0.24.0 // indirect
)
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q=
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s=
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1 h1:NVK+OqnavpyFmUiKfUMHrpvbCi2VFoWTrcpI7aDaJ2I=
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
github.com/xssnick/tonutils-go v1.9.9 h1:J0hVJI4LNEFHqgRHzpWTjFuv/Ga89OqLRUc9gxmjCoc=
github.com/xssnick/tonutils-go v1.9.9/go.mod h1:p1l1Bxdv9sz6x2jfbuGQUGJn6g5cqg7xsTp8rBHFoJY=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
160 changes: 160 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package main

import (
"flag"
"fmt"
"log"
"os"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"

"github.com/xssnick/tonutils-go/ton/wallet"
)

// Input parameters
type Config struct {
Suffix string
CaseSensitive bool
Bounce bool
Threads int
Testnet bool
}

func main() {
// Parse input parameters
config := parseFlags()

// Determine the number of threads (default: use all CPU cores if threads=0)
if config.Threads == 0 {
config.Threads = runtime.NumCPU()
}
log.Printf("Using %d threads\n", config.Threads)

// Channel to signal when a match is found
stopChan := make(chan struct{})

// Use sync.Once to ensure stopChan is closed only once
var once sync.Once

// Start tracking the number of processed wallets
var counter uint64
var wg sync.WaitGroup

// Start logging progress every second
go logProgress(&counter, stopChan)

// Start wallet generation and processing
for i := 0; i < config.Threads; i++ {
wg.Add(1)
go func() {
defer wg.Done()
processWallets(config, &counter, stopChan, &once)
}()
}

// Wait for all threads to finish
wg.Wait()
}

// parseFlags handles command-line input parameters
func parseFlags() Config {
suffix := flag.String("suffix", "", "Desired contract address suffix (required)")
caseSensitive := flag.Bool("case-sensitive", false, "Enable case-sensitive suffix matching (default: false)")
bounce := flag.Bool("bounce", false, "Enable bounceable address (default: false)")
threads := flag.Int("threads", 0, "Number of parallel threads (default: 0, meaning use all CPU cores)")
testnet := flag.Bool("testnet", false, "Use testnet (default: false)")
flag.Parse()

if *suffix == "" {
flag.PrintDefaults()
os.Exit(1)
}

return Config{
Suffix: *suffix,
CaseSensitive: *caseSensitive,
Bounce: *bounce,
Threads: *threads,
Testnet: *testnet,
}
}

// processWallets generates wallets, checks if the address matches the suffix, and stops on a match
func processWallets(config Config, counter *uint64, stopChan chan struct{}, once *sync.Once) {
for {
select {
case <-stopChan:
return
default:
// Generate the seed phrase
seed := wallet.NewSeed()

// Create a V5R1Final wallet using the seed
w, err := wallet.FromSeed(nil, seed, wallet.ConfigV5R1Final{
NetworkGlobalID: getNetworkID(config.Testnet),
Workchain: 0, // Base workchain
})
if err != nil {
log.Printf("Failed to create wallet: %v", err)
continue
}

// Get the wallet address
addr := w.WalletAddress()
// Get the address string (mainnet or testnet) and check bounceable flag
addressStr := addr.Testnet(config.Testnet).Bounce(config.Bounce).String()

// Case-sensitive or case-insensitive suffix comparison
if config.CaseSensitive {
if strings.HasSuffix(addressStr, config.Suffix) {
printFoundWallet(seed, addressStr)
once.Do(func() { close(stopChan) })
return
}
} else {
if strings.HasSuffix(strings.ToLower(addressStr), strings.ToLower(config.Suffix)) {
printFoundWallet(seed, addressStr)
once.Do(func() { close(stopChan) })
return
}
}

// Increment the counter
atomic.AddUint64(counter, 1)
}
}
}

// logProgress logs how many wallets were processed in the last second
func logProgress(counter *uint64, stopChan chan struct{}) {
var lastCount uint64
for {
select {
case <-stopChan:
return
case <-time.After(1 * time.Second):
currentCount := atomic.LoadUint64(counter)
processedLastSecond := currentCount - lastCount
lastCount = currentCount
log.Printf("Processed %d addresses in the last second\n", processedLastSecond)
}
}
}

// getNetworkID returns the correct network ID for mainnet or testnet
func getNetworkID(isTestnet bool) int32 {
if isTestnet {
return -3 // Testnet Global ID
}
return -239 // Mainnet Global ID
}

// printFoundWallet prints the found seed and wallet address
func printFoundWallet(seed []string, address string) {
fmt.Println("=== FOUND ===")
fmt.Println("Seed phrase:", strings.Join(seed, " "))
fmt.Println("Wallet address:", address)
}

0 comments on commit 16cf72c

Please sign in to comment.