首页 > 其他分享 >使用招商银行云直连服务提现

使用招商银行云直连服务提现

时间:2023-03-04 23:24:05浏览次数:42  
标签:提现 云直 JObject 招商银行 Add new byte Append string

以下代码的功能是用户可以实现业务中用户虚拟钱包的钱提现到用户银行卡,其实本质上是把商户的账户资金划转到用户银行卡,其实就是银行转账,相关代码如下:

///此方法存在部分业务代码,核心方法是doProcess方法且基本是可以复用的,其它的代码可以根据自身业务场景灵活处理;
public async Task<WithDrawResultDto> WithDrawToBank(TransferToBankDto transferToBankDto) { decimal balance = await _repository.WalletRepository.GetWalletBalance(new Contract.User.UserBasicDto() { WeChatId = transferToBankDto.WeChatId, }); if (balance < transferToBankDto.Amount) { return new WithDrawResultDto() { WithDrawResult = false, Message = "可用余额不够,请重新输入提现金额。" }; } long userId = await _repository.UserRepository.GetUserIdByWeChatId(transferToBankDto.WeChatId); if (userId == 0) { return new WithDrawResultDto() { WithDrawResult = false, Message = "用户不存在" }; } //bool walletToBankResult = await _walletService.WalletToBankAccount(transferToBankDto.WeChatId, userId, transferToBankDto.Amount, (int)WalletCashType.Withdrawing, yurRef); //if (walletToBankResult) //{ Log.Information("begin WithDraw call cloud direct"); string reqId = DCHelper.GetTime() + RandomHelper.GeneratorRandomStr(7); decimal amount = transferToBankDto.Amount; string bankCode = await _repository.BankRepository.QueryBankCodeByBankAccount(userId, transferToBankDto.BankAccount); string bankHolder = await _repository.BankRepository.QueryCardHolder(userId, transferToBankDto.BankAccount); Log.Information($"bankHolder:{bankHolder}"); //记录业务编号 //业务编号记录到数据库 // 组织发送报文 JObject obj = new JObject(); JObject req = new JObject(); JArray bb1paybmx1BodyArray = new JArray(); JObject bb1paybmx1Body = new JObject(); JObject bb1paybmx1Body2 = new JObject(); JArray bb1payopx1BodyArray = new JArray(); JObject bb1payopx1Body = new JObject(); JObject bb1payopx1Body2 = new JObject(); JObject head = new JObject(); head.Add("funcode", FunCode);// FunCode = "BB1PAYOP";功能代码 head.Add("userid", UID);//用户编号,与商户相关 head.Add("reqid", reqId); bb1paybmx1Body.Add("busCod", BusCod);//BusCod = "N02030";业务编码 bb1paybmx1Body.Add("busMod", BusMod);///业务模式 bb1paybmx1BodyArray.Add(bb1paybmx1Body); //bb1paybmx1Body2.Add("bb1paybmx1", bb1paybmx1BodyArray); JArray bb1payopx1 = new JArray(); bb1payopx1Body.Add("dbtAcc", CompanyCard);//公司账号 bb1payopx1Body.Add("crtAcc", transferToBankDto.BankAccount);//收款人账号 bb1payopx1Body.Add("crtNam", bankHolder);//持卡人姓名 bb1payopx1Body.Add("ccyNbr", CurrencyCode);//币种 CurrencyCode = "10";//10代表人民币 bb1payopx1Body.Add("trsAmt", amount.ToString("#0.00")); //bb1payopx1Body.Add("crtBnk", "招商银行深圳分行"); bb1payopx1Body.Add("bnkFlg", (bankCode == CMBCode ? "Y" : "N"));//CMBCodeCMBCode = "CMB";如果是招商银行,bnkFlg的取值是Y bb1payopx1Body.Add("stlChn", StlChn);//StlChn为R代表及时到账 bb1payopx1Body.Add("nusAge", "钱包提现到银行卡"); //bb1payopx1Body.Add("yurRef", "202008260078000033"); bb1payopx1Body.Add("yurRef", yurRef);//业务流水号,可以使用雪花算法生成 bb1payopx1BodyArray.Add(bb1payopx1Body); JObject jobjectBodyList = new JObject(); jobjectBodyList.Add("bb1paybmx1", bb1paybmx1BodyArray); jobjectBodyList.Add("bb1payopx1", bb1payopx1BodyArray); JObject jobjectBody = new JObject(); jobjectBody.Add("body", jobjectBodyList); jobjectBody.Add("head", head); JObject requestBody = new JObject(); requestBody.Add("request", jobjectBody); //bb1payopx1Body2.Add("bb1payopx1", bb1payopx1BodyArray); // 请求发送接收 var withDrawResult = doProcess(requestBody, FunCode); if (withDrawResult.WithDrawResult == true) { bool walletToBankResult = await _walletService.WalletToBankAccount(transferToBankDto.WeChatId, userId, transferToBankDto.Amount, (int)WalletCashType.Withdrawing, yurRef); WithDrawToBankRecord withDrawToBankRecord = new WithDrawToBankRecord (userId: userId, funcode: FunCode, reqid: reqId, busCod: BusCod, busMod: BusMod, dbtAcc: CompanyCard, crtAcc: transferToBankDto.BankAccount, crtNam: bankHolder, ccyNbr: CurrencyCode, trsAmt: amount, bnkFlg: (bankCode == CMBCode ? "Y" : "N"), stlChn: StlChn, nusAge: "钱包提现到银行卡", yurRef: yurRef.ToString(), withdrawStatus: 0,openId: transferToBankDto.OpenId); await _repository.RedPackageRepository.CreateWithDrawToBankRecord(withDrawToBankRecord); await WithDrawSendMsgToClient.SendMsgToClient(openId: transferToBankDto.OpenId, templageId: SuccessTemplateId, amount: amount, withdrawDatetime: DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), WithdrawToBankStatus.Success); } //更新出金时间 await _repository.BankRepository.UpdateWithDrawDateTimeAsync(userId, transferToBankDto.BankAccount); return withDrawResult; //} //else //{ // return new WithDrawResultDto() { WithDrawResult = false,Message="提现失败,请稍后重试." }; //} }

DCHelper辅助类

using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;

namespace Demo.Utils
{
    public class DCHelper
    {

        public static string SerialJsonOrdered(JObject json)
        {
            List<string> keyList = new List<string>();
            foreach (var x in json)
            {
                keyList.Add(x.Key);
            }
            string[] keyArray = keyList.ToArray();
            Array.Sort(keyArray, string.CompareOrdinal);
            StringBuilder appender = new StringBuilder();
            appender.Append("{");
            bool isFirstEle = true;
            foreach (var key in keyArray)
            {
                if (!isFirstEle)
                {
                    appender.Append(",");
                }
                Object val = json[key];
                if (val is JObject)
                {
                    appender.Append("\"").Append(key).Append("\":");
                    appender.Append(SerialJsonOrdered((JObject)val));
                }
                else if (val is JArray)
                {
                    JArray jarray = (JArray)val;
                    appender.Append("\"").Append(key).Append("\":[");
                    bool isFirstArrEle = true;
                    for (int i = 0; i < jarray.Count; i++)
                    {
                        if (!isFirstArrEle)
                        {
                            appender.Append(",");
                        }
                        Object obj = jarray[i];
                        if (obj is JObject)
                        {
                            appender.Append(SerialJsonOrdered((JObject)obj));
                        }
                        else
                        {
                            appender.Append(obj.ToString());
                        }
                        isFirstArrEle = false;
                    }
                    appender.Append("]");
                }
                else if (((JToken)val).Type == JTokenType.String)
                {
                    string value = val.ToString();
                    appender.Append("\"").Append(key).Append("\":").Append("\"").Append(value.Replace("\\", "\\\\")).Append("\"");
                }
                else if (((JToken)val).Type == JTokenType.Boolean)
                {
                    string value = val.ToString().ToLower();
                    appender.Append("\"").Append(key).Append("\":").Append(value);
                }
                else
                {
                    string value = val.ToString();
                    appender.Append("\"").Append(key).Append("\":").Append(value);
                }
                isFirstEle = false;
            }
            appender.Append("}");
            return appender.ToString();
        }


        public static String GetTime()
        {
            return DateTime.Now.ToString("yyyyMMddHHmmssfff");
        }
        public static String GetTime2()
        {
            return DateTime.Now.ToString("yyyyMMddHHmmss");
        }
        // 发送Post请求
        public static String DoPostForm(String httpUrl, Hashtable param)
        {
            Encoding encoding = Encoding.GetEncoding("utf-8");
            HttpWebResponse response = PostHttps(httpUrl, param, encoding);
            Stream stream = response.GetResponseStream();
            StreamReader sr = new StreamReader(stream);
            return sr.ReadToEnd();
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //信任所有https站点证书,不安全,请勿在生产环境中使用。
        }

        private static HttpWebResponse PostHttps(string url, Hashtable param, Encoding encoding)
        {
            HttpWebRequest request = null;
            //ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult); // 请勿在生产环境中使用该行程序
            request = WebRequest.Create(url) as HttpWebRequest;
            request.ProtocolVersion = HttpVersion.Version11;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.Timeout = 15000;
            request.KeepAlive = false;
            request.ReadWriteTimeout = 60000;

            byte[] data = encoding.GetBytes(CreateLinkString(param));
            request.ContentLength = data.Length;
            using (Stream stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            WebResponse res;
            try { res = request.GetResponse(); }
            catch (WebException e)
            {
                res = e.Response;
            }
            return (HttpWebResponse)res;
        }

        private static string CreateLinkString(Hashtable param)
        {
            IEnumerator keys = param.Keys.GetEnumerator();
            StringBuilder prestr = new StringBuilder();
            int i = 0;
            while (keys.MoveNext())
            {
                i++;
                string key = keys.Current as string;
                string value = param[key] as string;
                if (i == param.Count)
                {
                    prestr.Append(key).Append("=").Append(value);
                }
                else
                {
                    prestr.Append(key).Append("=").Append(value).Append("&");
                }
            }
            return prestr.ToString();
        }
    }
}

RandomHelper辅助类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Demo.Utils
{
    public static class RandomHelper
    {
        public static string GeneratorRandomStr(int len)
        {
            string chars = "0123456789abcdefghijklmnopqrstuvwxyz";

            Random randrom = new Random((int)DateTime.Now.Ticks);

            string str = "";
            for (int i = 0; i < len; i++)
            {
                str += chars[randrom.Next(chars.Length)];
            }
            return str;
        }
      
    }
}

 

核心方法:

 private WithDrawResultDto doProcess(JObject jObject, string FUNCODE)
        {
            JObject obj = new JObject();
            // 签名
            obj.Add("sigdat", "__signature_sigdat__");
            obj.Add("sigtim", DCHelper.GetTime2());
            jObject.Add("signature", obj);
            string source = DCHelper.SerialJsonOrdered(jObject);
            Console.WriteLine("签名原文: " + source);
            Log.Information($"{FUNCODE} request data is {source}");
            Encoding encoding = Encoding.UTF8;
            byte[] signature1 = DCCryptor.CMBSM2SignWithSM3(GetID_IV(), Convert.FromBase64String(privkey), encoding.GetBytes(source));//privkey是私钥
            string sigdat1 = Convert.ToBase64String(signature1);
            Console.WriteLine("签名结果: " + sigdat1);
            obj["sigdat"] = sigdat1;

            // SM4-CBC加密
            string plaintxt = jObject.ToString();
            Console.WriteLine("加密前req:  " + plaintxt);

            byte[] enInput = DCCryptor.CMBSM4EncryptWithCBC(encoding.GetBytes(sm4key), GetID_IV(), encoding.GetBytes(plaintxt));//sm4key是用户的对称密钥
            string req = Convert.ToBase64String(enInput);
            Console.WriteLine("加密后req:  " + req);
            Log.Information("begin send request to cloud direct");
            // 发送请求
            Hashtable map = new Hashtable();
            map.Add("UID", UID);
            map.Add("ALG", ALG_SM);//ALG_SM = "SM";采用国密算法
            map.Add("DATA", HttpUtility.UrlEncode(req, encoding));
            map.Add("FUNCODE", FUNCODE);
            string res = DCHelper.DoPostForm(URL, map);//访问招商银行的api请求地址:(测试环境:http://cdctest.cmburl.cn/cdcserver/api/v2;正式环境:https://cdc.cmbchina.com/cdcserver/api/v2)
            Log.Information("end request");
            Console.WriteLine("res:  " + res);
            Log.Information("DoPostForm {@res}", res);
            try
            {
                Convert.FromBase64String(res);
            }

            catch (Exception ex)
            {
                Console.WriteLine("访问返回错误.");
                Log.Information(" Convert.FromBase64String error  {@ex}", ex);
                return new()
                {
                    WithDrawResult = false,
                    Message = "访问返回错误."
                };
            }

            // 解密请求
            string resplain = encoding.GetString(DCCryptor.CMBSM4DecryptWithCBC(encoding.GetBytes(sm4key), GetID_IV(), Convert.FromBase64String(res)));
            Console.WriteLine("res decrypt: " + resplain);
            Log.Information($"{FUNCODE} response data is {resplain}");
            // 验签
            JObject object2 = JObject.Parse(resplain);
            JObject? object3 = object2["signature"] as JObject;
            string? resSign = object3?["sigdat"]?.ToString();
            object3["sigdat"] = "__signature_sigdat__";
            object2["signature"] = object3;
            string resSignSource = DCHelper.SerialJsonOrdered(object2);
            Console.WriteLine("验签原文: " + resSignSource);
            Console.WriteLine("验签签名值: " + resSign);
            bool verify = DCCryptor.CMBSM2VerifyWithSM3(GetID_IV(), Convert.FromBase64String(bankpubkey), encoding.GetBytes(resSignSource), Convert.FromBase64String(resSign));//bankpubkey:银行公钥
            Console.WriteLine("验签结果: " + verify);
            Log.Information($"验签结果:{verify}");
            if (verify)
            {
                //验签成功以后正常判断
                if (object2["response"]?["head"]?["resultcode"] is not null)
                {
                    string? resultCode = object2["response"]?["head"]?["resultcode"]?.ToString();
                    if (resultCode != "SUC0000")
                    {
                        Log.Information($"withdraw hava error,resultmsg is {object2["response"]?["head"]?["resultmsg"]?.ToString()}," +
                               $"resultcode is {object2["response"]?["head"]?["resultcode"]?.ToString()}");
                        return new()
                        {
                            WithDrawResult = false,
                            Message = object2["response"]?["head"]?["resultmsg"]?.ToString()
                        };
                    }
                    else
                    {
                        string[] errors = new[] { "F", "B", "R", "D", "C" };
                        string? rtnFlg = object2["response"]?["body"]?["bb1payopz1"][0]?["rtnFlg"]?.ToString();
                        if (object2["response"]?["body"]?["bb1payopz1"][0]?["reqSts"]?.ToString() == "FIN" && errors.Contains(rtnFlg))
                        {
                            Log.Information($"withdraw hava error,errTxt is {object2["response"]?["body"]?["bb1payopz1"][0]?["errTxt"]?.ToString()}," +
                                $"errCod is {object2["response"]?["body"]?["bb1payopz1"][0]?["errCod"]?.ToString()}");
                            return new()
                            {
                                WithDrawResult = false,
                                Message = object2["response"]?["body"]?["bb1payopz1"][0]?["errTxt"]?.ToString()
                            };
                        }
                    }
                }
            }
            else
            {
                Log.Error("验签失败");
                return new()
                {
                    WithDrawResult = false,
                    Message = "验签失败,请联系系统管理员。"
                };
            }
            return new() { WithDrawResult = true };
        }

私有方法

 private byte[] GetID_IV()
        {
            String uid = UID; // 请替换为实际的用户UID
            String userid = uid + "0000000000000000";
            return Encoding.UTF8.GetBytes(userid.Substring(0, 16));
        }

 

DCCryptor辅助类

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X9;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Math.EC;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Demo.Utils
{
    public class DCCryptor
    {
        public static byte[] CMBSM4EncryptWithCBC(byte[] key, byte[] iv, byte[] input)
        {
            if (key == null || iv == null || input == null)
            {
                throw new Exception("CMBSM4EncryptWithCBC 非法输入");
            }
            return CMBSM4Crypt(key, iv, input, true);
        }

        public static byte[] CMBSM4DecryptWithCBC(byte[] key, byte[] iv, byte[] input)
        {
            if (key == null || iv == null || input == null)
            {
                throw new Exception("CMBSM4DecryptWithCBC 非法输入");
            }
            return CMBSM4Crypt(key, iv, input, false);
        }

        public static byte[] CMBSM2SignWithSM3(byte[] id, byte[] privkey, byte[] msg)
        {
            if (privkey == null || msg == null)
            {
                throw new Exception("CMBSM2SignWithSM3 input error");
            }
            ECPrivateKeyParameters privateKey = EncodePrivateKey(privkey);
            SM2Signer signer = new SM2Signer();
            ParametersWithID parameters = new ParametersWithID(privateKey, id);
            signer.Init(true, parameters);
            signer.BlockUpdate(msg, 0, msg.Length);
            return DecodeDERSignature(signer.GenerateSignature());
        }

        public static bool CMBSM2VerifyWithSM3(byte[] id, byte[] pubkey, byte[] msg, byte[] signature)
        {

            if (pubkey == null || msg == null || signature == null)
            {
                throw new Exception("CMBSM2VerifyWithSM3 input error");
            }
            ECPublicKeyParameters publicKey = EncodePublicKey(pubkey);
            SM2Signer signer = new SM2Signer();
            ParametersWithID parameters = new ParametersWithID(publicKey, id);
            signer.Init(false, parameters);
            signer.BlockUpdate(msg, 0, msg.Length);
            return signer.VerifySignature(EncodeDERSignature(signature));
        }

        private static byte[] CMBSM4Crypt(byte[] keyBytes, byte[] iv, byte[] input, bool forEncrypt)
        {
            KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
            ParametersWithIV ivParameterSpec = new ParametersWithIV(key, iv);
            IBufferedCipher cipher = CipherUtilities.GetCipher("SM4/CBC/PKCS7Padding");
            cipher.Init(forEncrypt, ivParameterSpec);
            return cipher.DoFinal(input);
        }

        private static ECPrivateKeyParameters EncodePrivateKey(byte[] value)
        {
            BigInteger d = new BigInteger(1, value);
            X9ECParameters spec = ECNamedCurveTable.GetByName("sm2p256v1");
            ECDomainParameters ecParameters = new ECDomainParameters(spec.Curve, spec.G, spec.N, spec.H, spec.GetSeed());
            return new ECPrivateKeyParameters(d, ecParameters);
        }

        public static ECPublicKeyParameters EncodePublicKey(byte[] value)
        {
            byte[] x = new byte[32];
            byte[] y = new byte[32];
            Array.Copy(value, 1, x, 0, 32);
            Array.Copy(value, 33, y, 0, 32);
            BigInteger X = new BigInteger(1, x);
            BigInteger Y = new BigInteger(1, y);
            X9ECParameters spec = ECNamedCurveTable.GetByName("sm2p256v1");
            ECPoint Q = spec.Curve.CreatePoint(X, Y);
            ECDomainParameters ecParameters = new ECDomainParameters(spec.Curve, spec.G, spec.N, spec.H, spec.GetSeed());
            return new ECPublicKeyParameters(Q, ecParameters);
        }

        private static byte[] DecodeDERSignature(byte[] signature)
        {
            Asn1InputStream stream = new Asn1InputStream(signature);
            Asn1Sequence primitive = (Asn1Sequence)stream.ReadObject();
            System.Collections.IEnumerator enumeration = primitive.GetEnumerator();
            enumeration.MoveNext();
            BigInteger R = ((DerInteger)enumeration.Current).Value;
            enumeration.MoveNext();
            BigInteger S = ((DerInteger)enumeration.Current).Value;
            byte[] bytes = new byte[64];
            byte[] r = Format(R.ToByteArray());
            byte[] s = Format(S.ToByteArray());
            Array.Copy(r, 0, bytes, 0, 32);
            Array.Copy(s, 0, bytes, 32, 32);
            return bytes;
        }

        private static byte[] EncodeDERSignature(byte[] signature)
        {
            byte[] r = new byte[32];
            byte[] s = new byte[32];
            Array.Copy(signature, 0, r, 0, 32);
            Array.Copy(signature, 32, s, 0, 32);
            Asn1EncodableVector vector = new Asn1EncodableVector();
            vector.Add(new DerInteger(new BigInteger(1, r)));
            vector.Add(new DerInteger(new BigInteger(1, s)));
            return (new DerSequence(vector)).GetEncoded();
        }

        private static byte[] Format(byte[] value)
        {
            if (value.Length == 32)
            {
                return value;
            }
            else
            {
                byte[] bytes = new byte[32];
                if (value.Length > 32)
                {
                    Array.Copy(value, value.Length - 32, bytes, 0, 32);
                }
                else
                {
                    Array.Copy(value, 0, bytes, 32 - value.Length, value.Length);
                }
                return bytes;
            }
        }
    }
}

 

标签:提现,云直,JObject,招商银行,Add,new,byte,Append,string
From: https://www.cnblogs.com/cby-love/p/17179462.html

相关文章

  • php 微信提现
    将证书文件(3个)放在需要运行脚本的位置classCash{publicfunctionwxcash($openId,$money){$pub=['app_id'=>'######','mch_id'=>'######','key'=>'##......
  • 关于这个“微信提现”的问题,太炸裂了,以至于我写了段代码来验证!
    你好呀,我是歪歪。周末的时候,我在网上看到一个关于微信钱包提现时,手续费收取的一个问题。说真的,就这个问题吧,我个人觉得,放眼整个金融界,乃至于整个弱智吧,甚至于整个东半球......
  • 免费午餐结束!支付宝开始提现收费啦
    自今日起,支付宝将对提现收取0.1%的手续费,每人仅有累计2万元的免费提现额度。这意味着,免费提现服务将正式终结,而此前微信支付也对提现予以收费,第三方支付开始进入收费时......
  • 2023年1月中国数据库排行榜:OceanBase 持续两月登顶,前四甲青云直上开新局
    一元复始,万象更新。 国产数据库在经历过耕获菑畲的一年后,产品、生态、人才队伍建设等都取得了重大的进展。2023年1月 墨天轮中国数据库流行度排行 火热出炉,本月排行榜“......
  • VUE一个仿微信提现的功能
     UI组件用的是vant的键盘组件1:HTML部分<divclass="withdraw_page"><divclass="withdraw_page_header"><divclass="withdraw_page_header_......
  • 招商银行企银直连 招行云直连 国密SM2 SM4 PHP实现对接
    研究了好久好久,终于搞定了,参考了网上很多代码,网上所有的代码多多少少都有问题,要么是各种报错,要么是能签字不能验签,要么是有时候成功有时候失败。就截止2022.12.13日此时,网......
  • 腾讯云直播踩坑记录
    项目接入腾讯云直播SDK,期间遇到一些问题,记录下来。 U3D打包出的webGL项目。 1.本地测试OK,但是部署到外网后,无法唤起浏览器分享屏幕的弹窗原因:外网服务器没有配置ht......
  • 以太坊 layer2: optimism 源码学习(二) 提现原理
    作者:林冠宏/指尖下的幽灵。转载者,请:务必标明出处。掘金:https://juejin.im/user/1785262612681997博客:http://www.cnblogs.com/linguanh/GitHub:https://git......
  • Windpayer提现paypal到国内银行卡
    对于没有条件的小的2B/2C的卖家可以看这个这个!方便快捷,也就1%的手续费,方便快捷,且换汇牌价是银行牌价,价格合理合规,资金入账个人户头/公司户头。1.平台介绍通过Windpayer,......