internal/domain/ton_wallet.go
Rama main · réplica de lectura del repositorio original.
package domain
import (
"errors"
"strings"
"github.com/xssnick/tonutils-go/address"
)
// CanonicalTONAddress rejects anything but a mainnet basechain address.
func CanonicalTONAddress(raw string) (string, error) {
trimmed := strings.TrimSpace(raw)
var (
a *address.Address
err error
)
if strings.Contains(trimmed, ":") {
a, err = address.ParseRawAddr(trimmed)
} else {
a, err = address.ParseAddr(trimmed)
}
if err != nil || a == nil || a.IsAddrNone() || a.Workchain() != 0 || a.IsTestnetOnly() {
return "", errors.New("invalid mainnet address")
}
return a.StringRaw(), nil
}
// TelegramWalletInput recognizes what an operator typed as a Telegram identity
// instead of an address: rayo, @rayo, rayo.t.me, t.me/rayo. It returns the bare
// username; the wallet itself always comes from a verified record, never from
// the name.
func TelegramWalletInput(raw string) (string, bool) {
name := strings.ToLower(NormalizeUsername(raw))
if len(name) < 3 || len(name) > 32 {
return "", false
}
if name[0] < 'a' || name[0] > 'z' {
return "", false
}
for i := 0; i < len(name); i++ {
c := name[i]
switch {
case c >= 'a' && c <= 'z', c >= '0' && c <= '9', c == '_':
default:
return "", false
}
}
return name, true
}
// TONDNSName recognizes what an operator typed instead of an address: a .ton
// name, optionally written as a bare collectible username or with a leading @.
// The result is the normalized name whose wallet record must be looked up.
// WHY: a t.me link is a Telegram identity, never a wallet, so only names that
// end in the official .ton zone are accepted here and the address still comes
// from the on-chain wallet record, never from the name itself.
func TONDNSName(raw string) (string, bool) {
name := strings.ToLower(strings.TrimSpace(raw))
name = strings.TrimPrefix(name, "@")
if name == "" || len(name) > 128 {
return "", false
}
if !strings.Contains(name, ".") {
name += ".ton"
}
if !strings.HasSuffix(name, ".ton") {
return "", false
}
for _, label := range strings.Split(name, ".") {
if label == "" || len(label) > 63 {
return "", false
}
for i, r := range label {
switch {
case r >= 'a' && r <= 'z', r >= '0' && r <= '9':
case r == '-' && i > 0 && i < len(label)-1:
default:
return "", false
}
}
}
return name, true
}