mirror of
https://github.com/GMWalletApp/epusdt.git
synced 2026-07-07 10:16:15 +00:00
feat: support TON and USDT Jetton payments
- add TON chain, token, RPC, address normalization, and order matching support - add liteclient scanner with masterchain/shard catch-up and Jetton validation - add TON manual payment verification and focused tests
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/GMWalletApp/epusdt/model/dao"
|
||||
"github.com/GMWalletApp/epusdt/model/mdb"
|
||||
"github.com/GMWalletApp/epusdt/model/request"
|
||||
addressutil "github.com/GMWalletApp/epusdt/util/address"
|
||||
"github.com/dromara/carbon/v2"
|
||||
"github.com/shopspring/decimal"
|
||||
"gorm.io/gorm"
|
||||
@@ -39,9 +40,15 @@ func normalizeLockNetwork(network string) string {
|
||||
|
||||
func normalizeLockAddress(network, address string) string {
|
||||
address = strings.TrimSpace(address)
|
||||
if isEVMNetwork(normalizeLockNetwork(network)) {
|
||||
network = normalizeLockNetwork(network)
|
||||
if isEVMNetwork(network) {
|
||||
return strings.ToLower(address)
|
||||
}
|
||||
if network == mdb.NetworkTon {
|
||||
if raw, err := addressutil.TonRawAddressKey(address); err == nil {
|
||||
return raw
|
||||
}
|
||||
}
|
||||
return address
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/GMWalletApp/epusdt/internal/testutil"
|
||||
"github.com/GMWalletApp/epusdt/model/mdb"
|
||||
"github.com/xssnick/tonutils-go/address"
|
||||
)
|
||||
|
||||
func TestEvmTransactionLockAddressIsCaseInsensitive(t *testing.T) {
|
||||
@@ -156,3 +157,30 @@ func TestNonEvmTransactionLockAddressRemainsCaseSensitive(t *testing.T) {
|
||||
t.Fatalf("tron address lookup should remain case-sensitive, got trade id %q", gotTradeID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTonTransactionLockAddressUsesRawKey(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
bounceable := "EQC6KV4zs8TJtSZapOrRFmqSkxzpq-oSCoxekQRKElf4nC1I"
|
||||
addr := address.MustParseAddr(bounceable)
|
||||
nonBounce := addr.Bounce(false).String()
|
||||
|
||||
if err := LockTransaction(mdb.NetworkTon, bounceable, "TON", "trade-ton", 1.23, time.Hour); err != nil {
|
||||
t.Fatalf("lock ton transaction: %v", err)
|
||||
}
|
||||
gotTradeID, err := GetTradeIdByWalletAddressAndAmountAndToken(mdb.NetworkTon, nonBounce, "TON", 1.23)
|
||||
if err != nil {
|
||||
t.Fatalf("lookup ton lock: %v", err)
|
||||
}
|
||||
if gotTradeID != "trade-ton" {
|
||||
t.Fatalf("ton lock lookup = %q, want trade-ton", gotTradeID)
|
||||
}
|
||||
gotTradeID, err = GetTradeIdByWalletAddressAndAmountAndToken(mdb.NetworkTon, addr.StringRaw(), "TON", 1.23)
|
||||
if err != nil {
|
||||
t.Fatalf("lookup ton raw lock: %v", err)
|
||||
}
|
||||
if gotTradeID != "trade-ton" {
|
||||
t.Fatalf("ton raw lock lookup = %q, want trade-ton", gotTradeID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/GMWalletApp/epusdt/model/dao"
|
||||
"github.com/GMWalletApp/epusdt/model/mdb"
|
||||
addressutil "github.com/GMWalletApp/epusdt/util/address"
|
||||
"github.com/GMWalletApp/epusdt/util/constant"
|
||||
)
|
||||
|
||||
@@ -34,10 +35,23 @@ func normalizeWalletAddressByNetwork(network, address string) string {
|
||||
return address
|
||||
}
|
||||
|
||||
func normalizeWalletAddressByNetworkE(network, address string) (string, error) {
|
||||
network = normalizeWalletNetwork(network)
|
||||
address = strings.TrimSpace(address)
|
||||
if network == mdb.NetworkTon {
|
||||
return addressutil.NormalizeTonAddress(address)
|
||||
}
|
||||
return normalizeWalletAddressByNetwork(network, address), nil
|
||||
}
|
||||
|
||||
// AddWalletAddressWithNetwork 创建指定网络的钱包地址
|
||||
func AddWalletAddressWithNetwork(network, address string) (*mdb.WalletAddress, error) {
|
||||
network = normalizeWalletNetwork(network)
|
||||
address = normalizeWalletAddressByNetwork(network, address)
|
||||
var err error
|
||||
address, err = normalizeWalletAddressByNetworkE(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
exist, err := GetWalletAddressByNetworkAndAddress(network, address)
|
||||
if err != nil {
|
||||
@@ -75,9 +89,13 @@ func AddWalletAddressWithNetwork(network, address string) (*mdb.WalletAddress, e
|
||||
// GetWalletAddressByNetworkAndAddress 通过网络和地址查询
|
||||
func GetWalletAddressByNetworkAndAddress(network, address string) (*mdb.WalletAddress, error) {
|
||||
network = normalizeWalletNetwork(network)
|
||||
address = normalizeWalletAddressByNetwork(network, address)
|
||||
var err error
|
||||
address, err = normalizeWalletAddressByNetworkE(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
walletAddress := new(mdb.WalletAddress)
|
||||
err := dao.Mdb.Model(walletAddress).
|
||||
err = dao.Mdb.Model(walletAddress).
|
||||
Where("network = ?", network).
|
||||
Where("address = ?", address).
|
||||
Limit(1).Find(walletAddress).Error
|
||||
@@ -126,6 +144,12 @@ func GetAvailableWalletAddressByNetwork(network string) ([]mdb.WalletAddress, er
|
||||
for i := range list {
|
||||
list[i].Address = strings.ToLower(strings.TrimSpace(list[i].Address))
|
||||
}
|
||||
} else if network == mdb.NetworkTon {
|
||||
for i := range list {
|
||||
if normalized, err := addressutil.NormalizeTonAddress(list[i].Address); err == nil {
|
||||
list[i].Address = normalized
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
@@ -149,6 +173,12 @@ func GetAllWalletAddressByNetwork(network string) ([]mdb.WalletAddress, error) {
|
||||
for i := range list {
|
||||
list[i].Address = strings.ToLower(strings.TrimSpace(list[i].Address))
|
||||
}
|
||||
} else if network == mdb.NetworkTon {
|
||||
for i := range list {
|
||||
if normalized, err := addressutil.NormalizeTonAddress(list[i].Address); err == nil {
|
||||
list[i].Address = normalized
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/GMWalletApp/epusdt/internal/testutil"
|
||||
"github.com/GMWalletApp/epusdt/model/dao"
|
||||
"github.com/GMWalletApp/epusdt/model/mdb"
|
||||
"github.com/GMWalletApp/epusdt/util/constant"
|
||||
"github.com/xssnick/tonutils-go/address"
|
||||
)
|
||||
|
||||
func TestAddWalletAddressWithNetworkNormalizesEvmAddressToLowercase(t *testing.T) {
|
||||
@@ -81,3 +83,23 @@ func TestAddWalletAddressWithNetworkKeepsOriginalCaseForNonEvm(t *testing.T) {
|
||||
t.Fatalf("solana wallet address = %q, want %q", solRow.Address, solAddress)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddWalletAddressWithNetworkNormalizesTonAddressVariants(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
bounceable := "EQC6KV4zs8TJtSZapOrRFmqSkxzpq-oSCoxekQRKElf4nC1I"
|
||||
addr := address.MustParseAddr(bounceable)
|
||||
expected := addr.Bounce(false).String()
|
||||
|
||||
row, err := AddWalletAddressWithNetwork(mdb.NetworkTon, addr.StringRaw())
|
||||
if err != nil {
|
||||
t.Fatalf("add raw ton wallet: %v", err)
|
||||
}
|
||||
if row.Address != expected {
|
||||
t.Fatalf("stored TON address = %q, want %q", row.Address, expected)
|
||||
}
|
||||
if _, err = AddWalletAddressWithNetwork(mdb.NetworkTon, bounceable); err != constant.WalletAddressAlreadyExists {
|
||||
t.Fatalf("add equivalent ton wallet error = %v, want already exists", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user