Wallet Service Guide

๐Ÿ“‹ Overview

The Wallet Service is responsible for cryptocurrency wallet management across multiple blockchains (TON, TRON, Ethereum, BSC).

Port: 9092 (gRPC)
Status: โš ๏ธ Partial (Deposits working, Withdrawals blocked on Task 0.1)


๐Ÿ—๏ธ Architecture

Wallet Service
โ”œโ”€โ”€ internal/
โ”‚   โ”œโ”€โ”€ wallet/
โ”‚   โ”‚   โ”œโ”€โ”€ service/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ wallet.service.go      - Main business logic
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ signer/
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ interfaces.go       - Signer interface
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ factory.go          - Signer factory
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ ton_signer.go       - TON signing (Task 0.1)
โ”‚   โ”‚   โ”‚       โ”œโ”€โ”€ tron_signer.go      - TRON signing (Task 0.2)
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ twc/                - Trust Wallet Core (optional)
โ”‚   โ”‚   โ”œโ”€โ”€ domain/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ entity/
โ”‚   โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ wallet.entity.go    - Wallet model
โ”‚   โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ wallet_root.entity.go - HD wallet root
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ repository/             - DB repositories
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ service/
โ”‚   โ”‚   โ”‚       โ””โ”€โ”€ ton_wallet_generator_v4r2.go - TON wallet gen
โ”‚   โ”‚   โ””โ”€โ”€ transport/
โ”‚   โ”‚       โ””โ”€โ”€ grpc/                   - gRPC handlers
โ”‚   โ”œโ”€โ”€ balance/                        - Balance service (Task 0.5)
โ”‚   โ””โ”€โ”€ user/                           - User service
โ”œโ”€โ”€ migrations/                         - Database migrations
โ””โ”€โ”€ cmd/
    โ”œโ”€โ”€ server/                         - Main server
    โ””โ”€โ”€ migrator/                       - Migration runner

๐Ÿ”‘ Key Components

1. Wallet Generation

TON Wallet (v4R2) - WORKING โœ…

File: internal/wallet/domain/service/ton_wallet_generator_v4r2.go

generator := NewTONWalletGeneratorV4R2(encryptionKey)
wallet, root, err := generator.GenerateWallet(telegramID, "My TON Wallet", true)

// Creates:
// 1. 24-word mnemonic (BIP39 via tonutils-go)
// 2. ed25519 keypair
// 3. v4R2 wallet contract address (EQ... format)
// 4. Encrypts mnemonic (AES-256-GCM + PBKDF2)
// 5. Stores in database (wallet + wallet_root)

Generated Address Format: - Mainnet: EQCa1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z - Testnet: UQCa1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z - Workchain: 0 (mainnet) - Bounceable: Yes (default for user display)

TRON Wallet - TODO (Task 0.2)

Target: Generate proper T… addresses


2. Signer Interface

File: internal/wallet/service/signer/interfaces.go

type Signer interface {
    Address(pub PubKey, chain Chain) (string, error)
    SignTx(chain Chain, priv PrivKey, payload []byte) ([]byte, error)
}

type Deriver interface {
    FromMnemonic(m string, path string, curve Curve) (PrivKey, PubKey, error)
}

Current Status: - TON Signer: โŒ Placeholder (Task 0.1) - TRON Signer: โŒ Placeholder (Task 0.2) - Trust Wallet Core: ๐Ÿ”ง Framework ready (optional)


3. Database Schema

Wallets Table

CREATE TABLE wallets (
    id UUID PRIMARY KEY,
    user_id UUID NOT NULL,              -- Links to users.id
    telegram_id BIGINT NOT NULL,        -- Links to Telegram
    wallet_type VARCHAR(20),            -- 'hd' | 'connected' | 'hot'
    status VARCHAR(20),                 -- 'active' | 'inactive' | 'pending'
    address VARCHAR(255) NOT NULL,      -- Blockchain address
    public_key TEXT NOT NULL,           -- Public key
    network VARCHAR(50) NOT NULL,       -- 'TON' | 'TRON' | 'ETH' | 'BSC'
    derivation_path VARCHAR(100),       -- BIP44 path (for HD)
    xpub TEXT,                          -- Extended public key
    is_default BOOLEAN DEFAULT FALSE,   -- Default wallet for network
    source VARCHAR(20),                 -- 'internal' | 'walletconnect'
    created_at TIMESTAMP,
    updated_at TIMESTAMP
);

Wallet Roots Table

CREATE TABLE wallet_roots (
    id UUID PRIMARY KEY,
    telegram_id BIGINT NOT NULL,
    network VARCHAR(50) NOT NULL,
    encrypted_mnemonic TEXT NOT NULL,   -- AES-256-GCM encrypted
    xpub TEXT NOT NULL,
    encrypted_xprv TEXT NOT NULL,
    created_at TIMESTAMP,
    UNIQUE(telegram_id, network)        -- One root per user per chain
);

Indexes: - telegram_id (frequently queried) - address (for deposit detection) - user_id + network + is_default (default wallet lookup)


๐Ÿ”„ Workflows

Deposit Flow

1. User requests deposit address
        โ†“
2. WalletService.GetDepositAddress(userId, network)
        โ†“
3. Check for existing default wallet:
   SELECT * FROM wallets 
   WHERE user_id = ? AND network = ? AND is_default = true;
        โ†“
4. If not exists, create:
   - Generate mnemonic (tonutils-go)
   - Derive keypair  
   - Create address (v4R2 for TON)
   - Encrypt mnemonic
   - Store in DB (wallet + wallet_root)
        โ†“
5. Return address: "EQCa1b2c3d4e5f6g..."
        โ†“
6. Watcher monitors blockchain
        โ†“
7. Deposit detected โ†’ emit event
        โ†“
8. Accounting Service credits balance
        โ†“
9. User notified via Telegram

Withdrawal Flow (Needs Task 0.1!)

1. User requests withdrawal: 50 TON to external address
        โ†“
2. Accounting Service checks + locks balance
        โ†“
3. WalletService.ProcessWithdrawal(userId, amount, toAddress)
        โ†“
4. Get wallet root:
   SELECT encrypted_mnemonic FROM wallet_roots 
   WHERE telegram_id = ? AND network = 'TON';
        โ†“
5. Decrypt mnemonic (AES-256-GCM)
        โ†“
6. Derive private key (tonutils-go)
        โ†“
7. Sign transaction (Task 0.1 - CURRENTLY BROKEN!) โ—„โ”€โ”€โ”€ โŒ
   signer := NewSigner("TON")
   signature, err := signer.SignTx("TON", privateKey, txBytes)
   // ERROR: "ton signer not implemented"
        โ†“
8. Broadcast to blockchain
        โ†“
9. Update withdrawal status (tx_hash)
        โ†“
10. Accounting Service unlocks balance
        โ†“
11. User notified via Telegram

๐Ÿ” Security

Mnemonic Encryption

// Encryption (when wallet is created)
func (g *TONWalletGeneratorV4R2) EncryptData(mnemonic string) (string, error) {
    // 1. Generate random salt (16 bytes)
    // 2. Derive key (PBKDF2: 10,000 iterations, SHA256)
    // 3. AES-256-GCM encryption
    // 4. Return: hex(salt + ciphertext)
}

// Decryption (when signing withdrawal)
func (g *TONWalletGeneratorV4R2) DecryptData(encrypted string) (string, error) {
    // 1. Decode hex
    // 2. Extract salt (first 16 bytes)
    // 3. Derive key (same PBKDF2 params)
    // 4. AES-256-GCM decryption
    // 5. Return plaintext mnemonic
    // 6. MUST zero memory after use! โ—„โ”€โ”€โ”€ IMPORTANT
}

Key Management

// Encryption key from environment
encryptionKey := os.Getenv("WALLET_ENC_KEY")

// MUST be 32 bytes for AES-256
// MUST be different per environment (dev, staging, prod)
// MUST be rotated periodically
// MUST be stored securely (KMS/Vault in production)

Private Key Handling

// NEVER store private keys in database
// NEVER log private keys
// ALWAYS derive on-demand from mnemonic
// ALWAYS zero memory after use

// Good:
privateKey := deriveFromMnemonic(mnemonic)
defer zeroMemory(privateKey)  // Zero after use
signature := sign(privateKey, tx)
return signature

// Bad:
privateKey := deriveFromMnemonic(mnemonic)
wallet.PrivateKey = privateKey  // โŒ NEVER STORE

๐Ÿงช Testing

Unit Tests

cd services/wallet
go test ./internal/wallet/service/signer/ -v
go test ./internal/wallet/domain/service/ -v

Integration Tests

# Requires running database
go test -tags=integration ./...

Test Vectors (Golden Tests)

// Test with known mnemonic
mnemonic := "abandon abandon abandon ... art"
expectedAddress := "EQCa1b2c3d4e5f6g..."

generator := NewTONWalletGeneratorV4R2(testKey)
address, _ := generator.DeriveAddressFromMnemonic(mnemonic)

assert.Equal(t, expectedAddress, address)

๐Ÿ“Š Metrics

# Wallet operations
wallets_created_total{network}
wallets_active_total{network}
deposit_addresses_generated_total{network}

# Signing operations (when Task 0.1 complete)
transactions_signed_total{network, type}
signing_duration_seconds{network}
signing_errors_total{network, error_type}

# Mnemonic operations
mnemonics_encrypted_total
mnemonics_decrypted_total
encryption_duration_seconds
decryption_duration_seconds

๐Ÿš€ Usage Examples

Create Wallet (gRPC)

req := &wallet_pb.CreateWalletRequest{
    TelegramId: 123456789,
    Network: "TON",
    WalletType: "internal",
}

resp, err := walletClient.CreateWallet(ctx, req)
// Returns: {wallet_id, address, network}

Get Deposit Address (gRPC)

req := &wallet_pb.GetDepositAddressRequest{
    UserId: "550e8400-...",
    Network: "TON",
}

resp, err := walletClient.GetDepositAddress(ctx, req)
// Returns: {address: "EQCa1b2c...", network: "TON"}

Sign Withdrawal (After Task 0.1)

signer := signers.NewSigner(signers.Chain("TON"))
signature, err := signer.SignTx(
    signers.Chain("TON"),
    privateKey,
    transactionBytes,
)
// Returns: Signed transaction ready for broadcast

© 2025 GitiNext - Enterprise Crypto Infrastructure | GitHub | Website