增加显式C2C充值校验渠道
This commit is contained in:
parent
7609509f7f
commit
3210db25c4
@ -850,6 +850,8 @@ func normalizeRechargeProvider(providerCode string, chain string) (string, strin
|
|||||||
return "usdt", "TRON", nil
|
return "usdt", "TRON", nil
|
||||||
case "usdt_bep20", "bep20", "bsc", "bnb":
|
case "usdt_bep20", "bep20", "bsc", "bnb":
|
||||||
return "usdt", "BSC", nil
|
return "usdt", "BSC", nil
|
||||||
|
case "usdt_c2c", "c2c":
|
||||||
|
return "usdt", "C2C", nil
|
||||||
default:
|
default:
|
||||||
return "", "", errors.New("充值方式不正确")
|
return "", "", errors.New("充值方式不正确")
|
||||||
}
|
}
|
||||||
@ -865,6 +867,8 @@ func normalizeRechargeChain(chain string) string {
|
|||||||
return "TRON"
|
return "TRON"
|
||||||
case "bsc", "bnb", "bep20", "usdt_bep20":
|
case "bsc", "bnb", "bep20", "usdt_bep20":
|
||||||
return "BSC"
|
return "BSC"
|
||||||
|
case "c2c", "usdt_c2c":
|
||||||
|
return "C2C"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@ -879,6 +883,8 @@ func receiptProviderCode(order model.CoinSellerRechargeOrder) string {
|
|||||||
return "usdt_trc20"
|
return "usdt_trc20"
|
||||||
case "BSC":
|
case "BSC":
|
||||||
return "usdt_bep20"
|
return "usdt_bep20"
|
||||||
|
case "C2C":
|
||||||
|
return "usdt_c2c"
|
||||||
default:
|
default:
|
||||||
return "usdt"
|
return "usdt"
|
||||||
}
|
}
|
||||||
@ -903,6 +909,8 @@ func receiptChain(order model.CoinSellerRechargeOrder) string {
|
|||||||
return "trc20"
|
return "trc20"
|
||||||
case "BSC":
|
case "BSC":
|
||||||
return "bep20"
|
return "bep20"
|
||||||
|
case "C2C":
|
||||||
|
return "c2c"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,7 +79,7 @@ func (c *Client) FindUSDTTransfer(ctx context.Context, req ports.BinanceTransfer
|
|||||||
req.Coin = strings.ToUpper(strings.TrimSpace(req.Coin))
|
req.Coin = strings.ToUpper(strings.TrimSpace(req.Coin))
|
||||||
req.Network = strings.ToUpper(strings.TrimSpace(req.Network))
|
req.Network = strings.ToUpper(strings.TrimSpace(req.Network))
|
||||||
req.ToAddress = strings.TrimSpace(req.ToAddress)
|
req.ToAddress = strings.TrimSpace(req.ToAddress)
|
||||||
if req.ExternalID == "" || req.Coin == "" || req.Network == "" || req.ToAddress == "" || req.AmountMinor <= 0 {
|
if req.ExternalID == "" || req.Coin == "" || req.Network == "" || req.AmountMinor <= 0 {
|
||||||
return ports.BinanceTransferRecord{}, xerr.New(xerr.InvalidArgument, "binance transfer verification request is incomplete")
|
return ports.BinanceTransferRecord{}, xerr.New(xerr.InvalidArgument, "binance transfer verification request is incomplete")
|
||||||
}
|
}
|
||||||
serverTimeMS, err := c.serverTime(ctx)
|
serverTimeMS, err := c.serverTime(ctx)
|
||||||
@ -260,7 +260,8 @@ func matchDepositRecord(req ports.BinanceTransferLookupRequest, records []deposi
|
|||||||
if candidate.Status != 1 {
|
if candidate.Status != 1 {
|
||||||
return ports.BinanceTransferRecord{}, xerr.New(xerr.Conflict, "binance deposit status is not successful")
|
return ports.BinanceTransferRecord{}, xerr.New(xerr.Conflict, "binance deposit status is not successful")
|
||||||
}
|
}
|
||||||
if !strings.EqualFold(strings.TrimSpace(candidate.Address), strings.TrimSpace(req.ToAddress)) {
|
// Deposit History 属于具体链上入账,必须有预先配置的收款地址;允许空地址仅服务于随后独立校验的 Pay C2C 事实源。
|
||||||
|
if strings.TrimSpace(req.ToAddress) == "" || !strings.EqualFold(strings.TrimSpace(candidate.Address), strings.TrimSpace(req.ToAddress)) {
|
||||||
return ports.BinanceTransferRecord{}, xerr.New(xerr.Conflict, "binance deposit address mismatch")
|
return ports.BinanceTransferRecord{}, xerr.New(xerr.Conflict, "binance deposit address mismatch")
|
||||||
}
|
}
|
||||||
amountMinor, err := parseUSDTAmountMinor(candidate.Amount)
|
amountMinor, err := parseUSDTAmountMinor(candidate.Amount)
|
||||||
|
|||||||
@ -68,6 +68,8 @@ const (
|
|||||||
PaymentProviderUSDTTRC20 = "usdt_trc20"
|
PaymentProviderUSDTTRC20 = "usdt_trc20"
|
||||||
// PaymentProviderUSDTBEP20 是用户提交 BSC BEP20 链上交易哈希的 USDT 充值渠道。
|
// PaymentProviderUSDTBEP20 是用户提交 BSC BEP20 链上交易哈希的 USDT 充值渠道。
|
||||||
PaymentProviderUSDTBEP20 = "usdt_bep20"
|
PaymentProviderUSDTBEP20 = "usdt_bep20"
|
||||||
|
// PaymentProviderUSDTC2C 是 Binance Pay C2C 收款订单;它不绑定公链,也不要求链上收款地址。
|
||||||
|
PaymentProviderUSDTC2C = "usdt_c2c"
|
||||||
// ThirdPartyPaymentStatusActive 表示渠道或支付方式可用于 H5 下单。
|
// ThirdPartyPaymentStatusActive 表示渠道或支付方式可用于 H5 下单。
|
||||||
ThirdPartyPaymentStatusActive = "active"
|
ThirdPartyPaymentStatusActive = "active"
|
||||||
// ThirdPartyPaymentStatusDisabled 表示渠道或支付方式已被后台关闭。
|
// ThirdPartyPaymentStatusDisabled 表示渠道或支付方式已被后台关闭。
|
||||||
|
|||||||
@ -416,6 +416,8 @@ func NormalizePaymentProvider(provider string) string {
|
|||||||
return PaymentProviderUSDTTRC20
|
return PaymentProviderUSDTTRC20
|
||||||
case PaymentProviderUSDTBEP20:
|
case PaymentProviderUSDTBEP20:
|
||||||
return PaymentProviderUSDTBEP20
|
return PaymentProviderUSDTBEP20
|
||||||
|
case PaymentProviderUSDTC2C:
|
||||||
|
return PaymentProviderUSDTC2C
|
||||||
case PaymentProviderGooglePlay:
|
case PaymentProviderGooglePlay:
|
||||||
return PaymentProviderGooglePlay
|
return PaymentProviderGooglePlay
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -33,6 +33,9 @@ func (s *Service) VerifyCoinSellerRechargeReceipt(ctx context.Context, command l
|
|||||||
return s.verifyUSDTRechargeReceipt(ctx, command, "trc20", s.externalRecharge.USDTTRC20Enabled, s.externalRecharge.usdtTRC20AddressForApp(command.AppCode), s.tronUSDT)
|
return s.verifyUSDTRechargeReceipt(ctx, command, "trc20", s.externalRecharge.USDTTRC20Enabled, s.externalRecharge.usdtTRC20AddressForApp(command.AppCode), s.tronUSDT)
|
||||||
case ledger.PaymentProviderUSDTBEP20:
|
case ledger.PaymentProviderUSDTBEP20:
|
||||||
return s.verifyUSDTRechargeReceipt(ctx, command, "bep20", s.externalRecharge.USDTBEP20Enabled, s.externalRecharge.usdtBEP20AddressForApp(command.AppCode), s.bscUSDT)
|
return s.verifyUSDTRechargeReceipt(ctx, command, "bep20", s.externalRecharge.USDTBEP20Enabled, s.externalRecharge.usdtBEP20AddressForApp(command.AppCode), s.bscUSDT)
|
||||||
|
case ledger.PaymentProviderUSDTC2C:
|
||||||
|
// C2C 是 Binance 账户内收款事实,不属于 TRON/BSC;空地址和关闭的链上开关不影响只读查单。
|
||||||
|
return s.verifyUSDTRechargeReceipt(ctx, command, "c2c", false, "", nil)
|
||||||
default:
|
default:
|
||||||
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.InvalidArgument, "receipt provider is invalid")
|
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.InvalidArgument, "receipt provider is invalid")
|
||||||
}
|
}
|
||||||
@ -333,20 +336,23 @@ type receiptUSDTClient interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) verifyUSDTRechargeReceipt(ctx context.Context, command ledger.VerifyCoinSellerRechargeReceiptCommand, chain string, enabled bool, receiveAddress string, client receiptUSDTClient) (ledger.CoinSellerRechargeReceiptVerification, error) {
|
func (s *Service) verifyUSDTRechargeReceipt(ctx context.Context, command ledger.VerifyCoinSellerRechargeReceiptCommand, chain string, enabled bool, receiveAddress string, client receiptUSDTClient) (ledger.CoinSellerRechargeReceiptVerification, error) {
|
||||||
if !enabled || strings.TrimSpace(receiveAddress) == "" {
|
|
||||||
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.Unavailable, "usdt "+chain+" receipt verification is not configured")
|
|
||||||
}
|
|
||||||
snapshot := s.receiptSnapshot(command)
|
snapshot := s.receiptSnapshot(command)
|
||||||
snapshot.Chain = chain
|
snapshot.Chain = chain
|
||||||
snapshot.CurrencyCode = ledger.PaidCurrencyUSDT
|
snapshot.CurrencyCode = ledger.PaidCurrencyUSDT
|
||||||
snapshot.ProviderAmountMinor = command.USDMinorAmount
|
snapshot.ProviderAmountMinor = command.USDMinorAmount
|
||||||
snapshot.ProviderOrderID = command.ExternalOrderNo
|
snapshot.ProviderOrderID = command.ExternalOrderNo
|
||||||
snapshot.ReceiveAddress = strings.TrimSpace(receiveAddress)
|
snapshot.ReceiveAddress = strings.TrimSpace(receiveAddress)
|
||||||
if !isLikelyChainTransactionHash(command.ExternalOrderNo) {
|
if chain == "c2c" {
|
||||||
// Binance Pay C2C 订单号不属于某条公链;后台选择 TRC20 或 BEP20 只表示运营记录的支付币种。
|
// 查单来源由运营显式选择;C2C 只读取 Binance 账户事实,绝不从 TRON/BSC 隐式降级或猜测。
|
||||||
// 因此所有非链上哈希都必须先走 Binance 账户入账事实,不能把 BEP20 的 C2C 订单号误送给 BSC 链上客户端。
|
|
||||||
return s.verifyBinanceTransferReceipt(ctx, command, snapshot, binanceNetworkForReceiptChain(chain))
|
return s.verifyBinanceTransferReceipt(ctx, command, snapshot, binanceNetworkForReceiptChain(chain))
|
||||||
}
|
}
|
||||||
|
if !enabled || snapshot.ReceiveAddress == "" {
|
||||||
|
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.Unavailable, "usdt "+chain+" receipt verification is not configured")
|
||||||
|
}
|
||||||
|
if !isLikelyChainTransactionHash(command.ExternalOrderNo) {
|
||||||
|
// TRON/BSC 只接受标准交易哈希;非链上编号必须由运营明确改选 C2C,避免跨事实源误校验。
|
||||||
|
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.InvalidArgument, "usdt "+chain+" receipt requires transaction hash")
|
||||||
|
}
|
||||||
if client == nil {
|
if client == nil {
|
||||||
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.Unavailable, "usdt "+chain+" client is not configured")
|
return ledger.CoinSellerRechargeReceiptVerification{}, xerr.New(xerr.Unavailable, "usdt "+chain+" client is not configured")
|
||||||
}
|
}
|
||||||
@ -387,7 +393,7 @@ func (s *Service) verifyBinanceTransferReceipt(ctx context.Context, command ledg
|
|||||||
snapshot.ProviderOrderID = record.TxID
|
snapshot.ProviderOrderID = record.TxID
|
||||||
snapshot.ProviderAmountMinor = record.AmountMinor
|
snapshot.ProviderAmountMinor = record.AmountMinor
|
||||||
// Pay C2C 没有链上收款地址;只有 Deposit History 命中时才用 Binance 返回地址覆盖配置快照。
|
// Pay C2C 没有链上收款地址;只有 Deposit History 命中时才用 Binance 返回地址覆盖配置快照。
|
||||||
if strings.TrimSpace(record.Address) != "" {
|
if snapshot.Chain != "c2c" && strings.TrimSpace(record.Address) != "" {
|
||||||
snapshot.ReceiveAddress = record.Address
|
snapshot.ReceiveAddress = record.Address
|
||||||
}
|
}
|
||||||
snapshot.RawJSON = strings.TrimSpace(record.RawJSON)
|
snapshot.RawJSON = strings.TrimSpace(record.RawJSON)
|
||||||
@ -400,6 +406,8 @@ func binanceNetworkForReceiptChain(chain string) string {
|
|||||||
switch strings.ToLower(strings.TrimSpace(chain)) {
|
switch strings.ToLower(strings.TrimSpace(chain)) {
|
||||||
case "bep20":
|
case "bep20":
|
||||||
return "BSC"
|
return "BSC"
|
||||||
|
case "c2c":
|
||||||
|
return "C2C"
|
||||||
default:
|
default:
|
||||||
return "TRX"
|
return "TRX"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -529,7 +529,25 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20HashUsesTronGrid(t *testing.T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerifyCoinSellerRechargeReceiptUSDTTRC20OffchainUsesBinance(t *testing.T) {
|
func TestVerifyCoinSellerRechargeReceiptUSDTTRC20RejectsC2COrderNumber(t *testing.T) {
|
||||||
|
svc := walletservice.New(nil)
|
||||||
|
svc.SetTronUSDTClient(&fakeTronUSDTClient{})
|
||||||
|
svc.SetExternalRechargeConfig(walletservice.ExternalRechargeConfig{
|
||||||
|
USDTTRC20Enabled: true,
|
||||||
|
USDTTRC20Address: "TPlatformReceiveAddress",
|
||||||
|
})
|
||||||
|
_, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
||||||
|
AppCode: "lalu",
|
||||||
|
ProviderCode: ledger.PaymentProviderUSDTTRC20,
|
||||||
|
ExternalOrderNo: "440537037787594752",
|
||||||
|
USDMinorAmount: 20000,
|
||||||
|
})
|
||||||
|
if !xerr.IsCode(err, xerr.InvalidArgument) || !strings.Contains(err.Error(), "requires transaction hash") {
|
||||||
|
t.Fatalf("TRC20 must reject C2C order number without fallback: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyCoinSellerRechargeReceiptUSDTC2CUsesBinance(t *testing.T) {
|
||||||
tron := &fakeTronUSDTClient{err: xerr.New(xerr.Internal, "tron should not be called")}
|
tron := &fakeTronUSDTClient{err: xerr.New(xerr.Internal, "tron should not be called")}
|
||||||
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
||||||
TxID: "Off-chain transfer 388611987194",
|
TxID: "Off-chain transfer 388611987194",
|
||||||
@ -553,7 +571,7 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20OffchainUsesBinance(t *testing.
|
|||||||
})
|
})
|
||||||
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
||||||
AppCode: "aslan",
|
AppCode: "aslan",
|
||||||
ProviderCode: ledger.PaymentProviderUSDTTRC20,
|
ProviderCode: ledger.PaymentProviderUSDTC2C,
|
||||||
ExternalOrderNo: "388611987194",
|
ExternalOrderNo: "388611987194",
|
||||||
USDMinorAmount: 50000,
|
USDMinorAmount: 50000,
|
||||||
OrderDateMS: 1783344000000,
|
OrderDateMS: 1783344000000,
|
||||||
@ -561,10 +579,10 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20OffchainUsesBinance(t *testing.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("VerifyCoinSellerRechargeReceipt binance offchain failed: %v", err)
|
t.Fatalf("VerifyCoinSellerRechargeReceipt binance offchain failed: %v", err)
|
||||||
}
|
}
|
||||||
if !receipt.Verified || receipt.Status != "confirmed" || receipt.ProviderOrderID != "Off-chain transfer 388611987194" || receipt.ProviderAmountMinor != 50000 || receipt.ReceiveAddress != "TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN" {
|
if !receipt.Verified || receipt.Status != "confirmed" || receipt.ProviderOrderID != "Off-chain transfer 388611987194" || receipt.ProviderAmountMinor != 50000 || receipt.ReceiveAddress != "" {
|
||||||
t.Fatalf("binance offchain receipt snapshot mismatch: %+v", receipt)
|
t.Fatalf("binance offchain receipt snapshot mismatch: %+v", receipt)
|
||||||
}
|
}
|
||||||
if binance.calls != 1 || binance.req.AppCode != "aslan" || binance.req.ExternalID != "388611987194" || binance.req.Network != "TRX" || binance.req.ToAddress != "TNwqCkF8cnM4XiwjnbbKTfdZvFDqVoa1TN" || binance.req.AmountMinor != 50000 || binance.req.OrderTimeMS != 1783344000000 {
|
if binance.calls != 1 || binance.req.AppCode != "aslan" || binance.req.ExternalID != "388611987194" || binance.req.Network != "C2C" || binance.req.ToAddress != "" || binance.req.AmountMinor != 50000 || binance.req.OrderTimeMS != 1783344000000 {
|
||||||
t.Fatalf("binance offchain request mismatch: calls=%d req=%+v", binance.calls, binance.req)
|
t.Fatalf("binance offchain request mismatch: calls=%d req=%+v", binance.calls, binance.req)
|
||||||
}
|
}
|
||||||
if tron.lastTxHash != "" {
|
if tron.lastTxHash != "" {
|
||||||
@ -572,7 +590,7 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20OffchainUsesBinance(t *testing.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerifyCoinSellerRechargeReceiptUSDTTRC20PayKeepsConfiguredAddress(t *testing.T) {
|
func TestVerifyCoinSellerRechargeReceiptUSDTC2CPayKeepsNoChainAddress(t *testing.T) {
|
||||||
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
||||||
Source: "pay_history",
|
Source: "pay_history",
|
||||||
ID: "433527303245463552",
|
ID: "433527303245463552",
|
||||||
@ -593,7 +611,7 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20PayKeepsConfiguredAddress(t *te
|
|||||||
})
|
})
|
||||||
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
||||||
AppCode: "yumi",
|
AppCode: "yumi",
|
||||||
ProviderCode: ledger.PaymentProviderUSDTTRC20,
|
ProviderCode: ledger.PaymentProviderUSDTC2C,
|
||||||
ExternalOrderNo: "433527303245463552",
|
ExternalOrderNo: "433527303245463552",
|
||||||
USDMinorAmount: 10000,
|
USDMinorAmount: 10000,
|
||||||
OrderDateMS: 1779713682799,
|
OrderDateMS: 1779713682799,
|
||||||
@ -604,15 +622,15 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20PayKeepsConfiguredAddress(t *te
|
|||||||
if !receipt.Verified || receipt.Status != "confirmed" || receipt.ProviderOrderID != "P_A223BU5M4Y171116" || receipt.ProviderAmountMinor != 10000 {
|
if !receipt.Verified || receipt.Status != "confirmed" || receipt.ProviderOrderID != "P_A223BU5M4Y171116" || receipt.ProviderAmountMinor != 10000 {
|
||||||
t.Fatalf("Pay C2C receipt snapshot mismatch: %+v", receipt)
|
t.Fatalf("Pay C2C receipt snapshot mismatch: %+v", receipt)
|
||||||
}
|
}
|
||||||
if receipt.ReceiveAddress != "TYumiConfiguredChainAddress" {
|
if receipt.ReceiveAddress != "" {
|
||||||
t.Fatalf("Pay C2C must not erase configured chain address: %+v", receipt)
|
t.Fatalf("Pay C2C must not inherit an unrelated chain address: %+v", receipt)
|
||||||
}
|
}
|
||||||
if binance.req.OrderTimeMS != 1779713682799 {
|
if binance.req.OrderTimeMS != 1779713682799 {
|
||||||
t.Fatalf("coin seller order time must bound Pay History query: %+v", binance.req)
|
t.Fatalf("coin seller order time must bound Pay History query: %+v", binance.req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerifyCoinSellerRechargeReceiptUSDTBEP20PayUsesBinance(t *testing.T) {
|
func TestVerifyCoinSellerRechargeReceiptUSDTC2CPayUsesBinance(t *testing.T) {
|
||||||
bsc := &fakeTronUSDTClient{err: xerr.New(xerr.Internal, "bsc chain client should not be called")}
|
bsc := &fakeTronUSDTClient{err: xerr.New(xerr.Internal, "bsc chain client should not be called")}
|
||||||
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
||||||
Source: "pay_history",
|
Source: "pay_history",
|
||||||
@ -635,7 +653,7 @@ func TestVerifyCoinSellerRechargeReceiptUSDTBEP20PayUsesBinance(t *testing.T) {
|
|||||||
})
|
})
|
||||||
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
||||||
AppCode: "yumi",
|
AppCode: "yumi",
|
||||||
ProviderCode: ledger.PaymentProviderUSDTBEP20,
|
ProviderCode: ledger.PaymentProviderUSDTC2C,
|
||||||
ExternalOrderNo: "440537037787594752",
|
ExternalOrderNo: "440537037787594752",
|
||||||
USDMinorAmount: 20000,
|
USDMinorAmount: 20000,
|
||||||
OrderDateMS: 1784017140000,
|
OrderDateMS: 1784017140000,
|
||||||
@ -646,18 +664,49 @@ func TestVerifyCoinSellerRechargeReceiptUSDTBEP20PayUsesBinance(t *testing.T) {
|
|||||||
if !receipt.Verified || receipt.Status != "confirmed" || receipt.ProviderOrderID != "P_C2C_BEP20_RECEIPT" || receipt.ProviderAmountMinor != 20000 {
|
if !receipt.Verified || receipt.Status != "confirmed" || receipt.ProviderOrderID != "P_C2C_BEP20_RECEIPT" || receipt.ProviderAmountMinor != 20000 {
|
||||||
t.Fatalf("BEP20 Pay C2C receipt snapshot mismatch: %+v", receipt)
|
t.Fatalf("BEP20 Pay C2C receipt snapshot mismatch: %+v", receipt)
|
||||||
}
|
}
|
||||||
if receipt.ReceiveAddress != "0xYumiConfiguredBSCAddress" {
|
if receipt.ReceiveAddress != "" {
|
||||||
t.Fatalf("BEP20 Pay C2C must keep configured chain address: %+v", receipt)
|
t.Fatalf("C2C must not persist an unrelated chain address: %+v", receipt)
|
||||||
}
|
}
|
||||||
if binance.calls != 1 || binance.req.Network != "BSC" || binance.req.ExternalID != "440537037787594752" || binance.req.AmountMinor != 20000 {
|
if binance.calls != 1 || binance.req.Network != "C2C" || binance.req.ExternalID != "440537037787594752" || binance.req.AmountMinor != 20000 {
|
||||||
t.Fatalf("BEP20 Pay C2C must use Binance transfer lookup: calls=%d req=%+v", binance.calls, binance.req)
|
t.Fatalf("C2C must use Binance transfer lookup: calls=%d req=%+v", binance.calls, binance.req)
|
||||||
}
|
}
|
||||||
if bsc.lastTxHash != "" {
|
if bsc.lastTxHash != "" {
|
||||||
t.Fatalf("BEP20 Pay C2C order id must not call BSC chain client: %+v", bsc)
|
t.Fatalf("BEP20 Pay C2C order id must not call BSC chain client: %+v", bsc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVerifyCoinSellerRechargeReceiptUSDTTRC20OffchainMissingBinanceAccount(t *testing.T) {
|
func TestVerifyCoinSellerRechargeReceiptUSDTC2CDoesNotRequireChainConfig(t *testing.T) {
|
||||||
|
binance := &fakeBinanceClient{record: walletservice.BinanceTransferRecord{
|
||||||
|
Source: "pay_history",
|
||||||
|
TxID: "P_C2C_LALU_RECEIPT",
|
||||||
|
Coin: ledger.PaidCurrencyUSDT,
|
||||||
|
Status: 1,
|
||||||
|
Amount: "200.00000000",
|
||||||
|
AmountMinor: 20000,
|
||||||
|
}}
|
||||||
|
svc := walletservice.New(nil)
|
||||||
|
svc.SetBinanceClient(binance)
|
||||||
|
// Lalu 只校验 Binance C2C 收款事实时不需要开启 BSC RPC,也不需要伪造一个链上收款地址。
|
||||||
|
svc.SetExternalRechargeConfig(walletservice.ExternalRechargeConfig{})
|
||||||
|
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
||||||
|
AppCode: "lalu",
|
||||||
|
ProviderCode: ledger.PaymentProviderUSDTC2C,
|
||||||
|
ExternalOrderNo: "440537037787594752",
|
||||||
|
USDMinorAmount: 20000,
|
||||||
|
OrderDateMS: 1784017620000,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BEP20 Pay C2C must not require chain config: %v", err)
|
||||||
|
}
|
||||||
|
if !receipt.Verified || receipt.ProviderOrderID != "P_C2C_LALU_RECEIPT" {
|
||||||
|
t.Fatalf("BEP20 Pay C2C receipt mismatch without chain config: %+v", receipt)
|
||||||
|
}
|
||||||
|
if binance.calls != 1 || binance.req.ToAddress != "" || binance.req.Network != "C2C" {
|
||||||
|
t.Fatalf("BEP20 Pay C2C lookup mismatch without chain config: calls=%d req=%+v", binance.calls, binance.req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyCoinSellerRechargeReceiptUSDTC2CMissingBinanceAccount(t *testing.T) {
|
||||||
binance := &fakeBinanceClient{err: xerr.New(xerr.Unavailable, "binance account is not configured")}
|
binance := &fakeBinanceClient{err: xerr.New(xerr.Unavailable, "binance account is not configured")}
|
||||||
svc := walletservice.New(nil)
|
svc := walletservice.New(nil)
|
||||||
svc.SetBinanceClient(binance)
|
svc.SetBinanceClient(binance)
|
||||||
@ -667,7 +716,7 @@ func TestVerifyCoinSellerRechargeReceiptUSDTTRC20OffchainMissingBinanceAccount(t
|
|||||||
})
|
})
|
||||||
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
receipt, err := svc.VerifyCoinSellerRechargeReceipt(context.Background(), ledger.VerifyCoinSellerRechargeReceiptCommand{
|
||||||
AppCode: "yumi",
|
AppCode: "yumi",
|
||||||
ProviderCode: ledger.PaymentProviderUSDTTRC20,
|
ProviderCode: ledger.PaymentProviderUSDTC2C,
|
||||||
ExternalOrderNo: "388611987194",
|
ExternalOrderNo: "388611987194",
|
||||||
USDMinorAmount: 50000,
|
USDMinorAmount: 50000,
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user