172 lines
5.5 KiB
Go
172 lines
5.5 KiB
Go
package binance
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"hyapp/pkg/xerr"
|
|
"hyapp/services/wallet-service/internal/config"
|
|
"hyapp/services/wallet-service/internal/service/wallet/ports"
|
|
)
|
|
|
|
func TestFindUSDTDepositMatchesOffchainTransferAndSignedRequest(t *testing.T) {
|
|
var sawDepositRequest bool
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.URL.Path {
|
|
case "/api/v3/time":
|
|
_, _ = w.Write([]byte(`{"serverTime":1783345000000}`))
|
|
case "/sapi/v1/capital/deposit/hisrec":
|
|
sawDepositRequest = true
|
|
if r.Header.Get("X-MBX-APIKEY") != "api-lalu" {
|
|
t.Fatalf("X-MBX-APIKEY mismatch")
|
|
}
|
|
values := r.URL.Query()
|
|
signature := values.Get("signature")
|
|
values.Del("signature")
|
|
if signature != signQueryString(values.Encode(), "secret-lalu") {
|
|
t.Fatalf("signature mismatch: query=%s signature=%s", values.Encode(), signature)
|
|
}
|
|
if values.Get("timestamp") != "1783345000000" || values.Get("recvWindow") != "10000" || values.Get("coin") != "USDT" || values.Get("limit") != "1000" {
|
|
t.Fatalf("signed deposit query mismatch: %s", values.Encode())
|
|
}
|
|
if values.Get("endTime") != "1783345000000" || values.Get("startTime") != "1775569000000" {
|
|
t.Fatalf("deposit bounded window mismatch: %s", values.Encode())
|
|
}
|
|
_, _ = w.Write([]byte(`[{
|
|
"id":"deposit-1",
|
|
"amount":"500.00000000",
|
|
"coin":"USDT",
|
|
"network":"TRX",
|
|
"status":1,
|
|
"address":"TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN",
|
|
"txId":"Off-chain transfer 388611987194",
|
|
"transferType":1,
|
|
"insertTime":1783344000000,
|
|
"completeTime":1783344025000,
|
|
"confirmTimes":"1/1",
|
|
"unlockConfirm":0,
|
|
"walletType":0
|
|
}]`))
|
|
default:
|
|
http.NotFound(w, r)
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := New(config.BinanceConfig{
|
|
Enabled: true,
|
|
APIBaseURL: server.URL,
|
|
RecvWindow: 10000,
|
|
HTTPTimeout: time.Second,
|
|
Lalu: config.BinanceAccountConfig{
|
|
APIKey: "api-lalu",
|
|
APISecretKey: "secret-lalu",
|
|
},
|
|
})
|
|
record, err := client.FindUSDTDeposit(context.Background(), ports.BinanceDepositLookupRequest{
|
|
AppCode: "lalu",
|
|
ExternalID: "388611987194",
|
|
Coin: "USDT",
|
|
Network: "TRX",
|
|
ToAddress: "TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN",
|
|
AmountMinor: 50000,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("FindUSDTDeposit failed: %v", err)
|
|
}
|
|
if !sawDepositRequest {
|
|
t.Fatalf("deposit history endpoint was not called")
|
|
}
|
|
if record.TxID != "Off-chain transfer 388611987194" || record.AmountMinor != 50000 || record.Network != "TRX" || !strings.Contains(record.RawJSON, `"txId"`) {
|
|
t.Fatalf("deposit record mismatch: %+v", record)
|
|
}
|
|
}
|
|
|
|
func TestFindUSDTDepositRejectsMismatches(t *testing.T) {
|
|
baseReq := ports.BinanceDepositLookupRequest{
|
|
AppCode: "lalu",
|
|
ExternalID: "388611987194",
|
|
Coin: "USDT",
|
|
Network: "TRX",
|
|
ToAddress: "TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN",
|
|
AmountMinor: 50000,
|
|
}
|
|
baseRecord := depositRecord{
|
|
Amount: "500",
|
|
Coin: "USDT",
|
|
Network: "TRX",
|
|
Status: 1,
|
|
Address: "TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN",
|
|
TxID: "Off-chain transfer 388611987194",
|
|
}
|
|
cases := []struct {
|
|
name string
|
|
mutate func(*depositRecord)
|
|
message string
|
|
}{
|
|
{name: "status", mutate: func(r *depositRecord) { r.Status = 0 }, message: "status is not successful"},
|
|
{name: "network", mutate: func(r *depositRecord) { r.Network = "BSC" }, message: "network mismatch"},
|
|
{name: "address", mutate: func(r *depositRecord) { r.Address = "TDifferentAddress" }, message: "address mismatch"},
|
|
{name: "amount", mutate: func(r *depositRecord) { r.Amount = "499.99" }, message: "amount mismatch"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
record := baseRecord
|
|
tc.mutate(&record)
|
|
_, err := matchDepositRecord(baseReq, []depositRecord{record})
|
|
if !xerr.IsCode(err, xerr.Conflict) || !strings.Contains(err.Error(), tc.message) {
|
|
t.Fatalf("expected conflict %q, got %v", tc.message, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFindUSDTDepositMissingAccountReturnsConfiguredError(t *testing.T) {
|
|
client := New(config.BinanceConfig{
|
|
Enabled: true,
|
|
APIBaseURL: "https://binance.invalid",
|
|
Lalu: config.BinanceAccountConfig{
|
|
APIKey: "api-lalu",
|
|
APISecretKey: "secret-lalu",
|
|
},
|
|
})
|
|
_, err := client.FindUSDTDeposit(context.Background(), ports.BinanceDepositLookupRequest{
|
|
AppCode: "aslan",
|
|
ExternalID: "388611987194",
|
|
Coin: "USDT",
|
|
Network: "TRX",
|
|
ToAddress: "TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN",
|
|
AmountMinor: 50000,
|
|
})
|
|
if !xerr.IsCode(err, xerr.Unavailable) || !strings.Contains(err.Error(), "binance account is not configured") {
|
|
t.Fatalf("missing account should be explicit, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestDepositTxIDMatchesOffchainVariants(t *testing.T) {
|
|
if !depositTxIDMatches("Off-chain transfer 388611987194", "388611987194") {
|
|
t.Fatalf("plain off-chain id should match Binance txId")
|
|
}
|
|
if !depositTxIDMatches("Off-chain transfer 388611987194", "Off-chain transfer 388611987194") {
|
|
t.Fatalf("full off-chain txId should match itself")
|
|
}
|
|
if depositTxIDMatches("Off-chain transfer 388611987194", "388611987195") {
|
|
t.Fatalf("different off-chain id must not match")
|
|
}
|
|
}
|
|
|
|
func TestSignQueryStringStable(t *testing.T) {
|
|
values := url.Values{}
|
|
values.Set("coin", "USDT")
|
|
values.Set("timestamp", "1783345000000")
|
|
signature := signQueryString(values.Encode(), "secret-lalu")
|
|
if signature != signQueryString("coin=USDT×tamp=1783345000000", "secret-lalu") {
|
|
t.Fatalf("signature must be based on encoded query string")
|
|
}
|
|
}
|