trading-order-admin/src/main/java/com/yami/trading/admin/task/IcoTask.java
@@ -3,22 +3,31 @@ import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.DateTime; import cn.hutool.core.lang.Console; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpStatus; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yami.trading.api.UD.*; import com.yami.trading.bean.ico.domain.Ico; import com.yami.trading.bean.item.domain.Item; import com.yami.trading.bean.model.ChannelBlockchain; import com.yami.trading.common.domain.Result; import com.yami.trading.common.util.ApplicationContextUtils; import com.yami.trading.common.util.StringUtils; import com.yami.trading.huobi.data.internal.KlineInitService; import com.yami.trading.security.common.enums.CryptoCurrencyEnum; import com.yami.trading.security.common.util.SecurityUtils; import com.yami.trading.service.ico.IcoService; import com.yami.trading.service.item.ItemService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.*; import java.util.stream.Collectors; @@ -38,6 +47,55 @@ @Autowired private KlineInitService klineInitService; @Autowired UdunClient udunClient; @Autowired RedisTemplate redisTemplate; //@Scheduled(cron = "*/5 * * * * ?") public void test() { String coin = "usdt"; List<ChannelBlockchain> data = new ArrayList<ChannelBlockchain>(); Map<String, List<CryptoCurrencyEnum>> allGroupedByCoin = CryptoCurrencyEnum.getAllGroupedByCoin(); List<CryptoCurrencyEnum> currencyEnums = allGroupedByCoin.get(coin); try { String partyId = SecurityUtils.getUser().getUserId(); //获取u盾地址 //获取商户支持币种 List<Coin> coinList = udunClient.listSupportCoin(false); currencyEnums.forEach((currencyEnum) -> { String coinName = currencyEnum.getName(); Coin c = coinList.stream().filter(x -> x.getName().equals(coinName)).findFirst().orElse(null); if (c != null) { ChannelBlockchain rechargeAddressVo = new ChannelBlockchain(); //创建地址 Address address; String ress = (String)redisTemplate.opsForValue().get(partyId + coinName); if(StringUtils.isNotEmpty(ress)){ rechargeAddressVo.setAddress(ress); rechargeAddressVo.setCoin(coinName); rechargeAddressVo.setBlockchain_name(coinName); rechargeAddressVo.setAuto(false); rechargeAddressVo.setImg(null); }else{ address = udunClient.createAddress(c.getMainCoinType(),null,null); rechargeAddressVo.setAddress(address.getAddress()); rechargeAddressVo.setCoin(coinName); rechargeAddressVo.setBlockchain_name(coinName); rechargeAddressVo.setAuto(false); rechargeAddressVo.setImg(null); redisTemplate.opsForValue().set(partyId + coinName, address.getAddress()); } data.add(rechargeAddressVo); } }); }catch (Exception e){ e.printStackTrace(); log.error("获取充值地址错误:",e); } } /** * ico转入产品 */ trading-order-admin/src/main/java/com/yami/trading/api/UD/UdunClient.java
@@ -6,41 +6,43 @@ import cn.hutool.json.JSONUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; @Component public class UdunClient implements UdunApi { private static Logger logger = LoggerFactory.getLogger(UdunClient.class); /** * UDUN API Gateway */ private final String gateway; /** * UDUN Merchant Number */ private final String merchantId; private final String gateway = "https://sig11.udun.io"; /** * UDUN Merchant Key */ private final String merchantKey; private final String merchantKey = "871fb1a18afd7229f5e62e4cba5016a6"; /** * Callback to business system * UDUN Merchant Number */ private final String defaultCallBackUrl; private final String merchantId = "321127"; public UdunClient(String gateway, String merchantId, String merchantKey, String defaultCallBackUrl) { this.gateway = gateway; this.merchantId = merchantId; this.merchantKey = merchantKey; this.defaultCallBackUrl = defaultCallBackUrl; } /** * Callback 充值 */ private final String defaultCallBackUrl = "https://syjysapi.yanshiz.com/api/channelBlockchain!rechargeCallback.action"; /** * Callback 提币 */ private final String withdrawCallBackUrl = "https://syjysapi.yanshiz.com/api/withdraw/withdrawCallback.action"; @Override public Address createAddress(String mainCoinType) throws UdunException { @@ -56,7 +58,7 @@ public Address createAddress(String mainCoinType, String alias, String walletId, String callUrl) throws UdunException{ Map<String, String> params = new HashMap<>(); params.put("merchantId", merchantId); params.put("coinType", mainCoinType); params.put("mainCoinType", mainCoinType); params.put("callUrl", callUrl); params.put("walletId", walletId); params.put("alias", alias); @@ -71,7 +73,7 @@ @Override public ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo) { return withdraw(address, amount, mainCoinType, coinType, businessId, memo, defaultCallBackUrl); return withdraw(address, amount, mainCoinType, coinType, businessId, memo, withdrawCallBackUrl); } @Override @@ -90,7 +92,7 @@ @Override public ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo) { return autoWithdraw(address, amount, mainCoinType, coinType, businessId, memo, defaultCallBackUrl); return autoWithdraw(address, amount, mainCoinType, coinType, businessId, memo, withdrawCallBackUrl); } @Override @@ -129,4 +131,9 @@ } return JSONUtil.toList(JSONUtil.parseArray(result.getData()), Coin.class); } public boolean checkSign(String timestamp, String nonce, String body, String sign) { String checkSign = UdunUtils.sign(merchantKey, timestamp, nonce, body); return checkSign.equals(sign); } } trading-order-admin/src/main/java/com/yami/trading/api/UD/UdunUtils.java
@@ -81,8 +81,4 @@ return SecureUtil.md5(raw); } public static boolean checkSign(String key, String timestamp, String nonce, String body, String sign) { String checkSign = sign(key, timestamp, nonce, body); return checkSign.equals(sign); } } trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
@@ -1,12 +1,21 @@ package com.yami.trading.api.controller; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpStatus; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fasterxml.jackson.databind.ObjectMapper; import com.yami.trading.api.UD.*; import com.yami.trading.bean.model.CapitaltWallet; import com.yami.trading.bean.model.RechargeBlockchainOrder; import com.yami.trading.bean.model.Withdraw; import com.yami.trading.common.constants.Constants; import com.yami.trading.common.domain.Result; import com.yami.trading.common.exception.BusinessException; import com.yami.trading.common.exception.YamiShopBindException; import com.yami.trading.common.util.Arith; import com.yami.trading.common.util.C2cLock; import com.yami.trading.common.util.DateUtils; import com.yami.trading.common.util.StringUtils; import com.yami.trading.security.common.util.SecurityUtils; @@ -16,12 +25,14 @@ import com.yami.trading.service.syspara.SysparaService; import com.yami.trading.service.user.UserService; import com.yami.trading.service.user.WalletLogService; import com.yami.trading.sys.model.SysUser; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.math.BigDecimal; import java.text.DecimalFormat; @@ -50,6 +61,9 @@ @Autowired CapitaltWalletService capitaltWalletService; @Autowired UdunClient udunClient; /** * 首次进入页面,传递session_token */ @@ -77,6 +91,8 @@ public Result apply(String session_token, String safeword, String amount, String from, String currency, String channel){ Result resultObject=new Result(); try { String partyId = SecurityUtils.getUser().getUserId(); String error = this.verif(amount); if (!StringUtils.isNullOrEmpty(error)) { @@ -118,10 +134,74 @@ withdraw.setAddress(from); withdraw.setCurrency(currency); withdraw.setTx(""); //获取商户支持币种 List<Coin> coinList = udunClient.listSupportCoin(false); Coin coin = coinList.stream().filter(x -> x.getName().equals(channel)).findFirst().orElse(null); if (coin == null) { throw new YamiShopBindException("不支持的提现币种"); } // 保存 this.withdrawService.saveApply(withdraw, channel, null); return Result.succeed(null); ResultMsg resultMsg = udunClient.withdraw(from, withdraw.getVolume(), coin.getMainCoinType(), coin.getCoinType(), withdraw.getOrderNo(), null); if (resultMsg.getCode() != HttpStatus.HTTP_OK) { log.error("withdraw:{}", JSONUtil.toJsonStr(resultMsg)); throw new UdunException(resultMsg.getCode(), resultMsg.getMessage()); } resultObject.setCode(0); } catch (UdunException e) { resultObject.setCode(1); resultObject.setMsg(e.getMessage()); log.error("error:" + e.getMessage()); throw e; } catch (Throwable t) { resultObject.setCode(1); resultObject.setMsg(t.getMessage()); log.error("error: {}", t.getMessage()); throw new RuntimeException(t); } return resultObject; } @PostMapping("withdrawCallback.action") public ResultMsg withdrawCallback(HttpServletRequest request){ String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String sign = request.getParameter("sign"); String body = request.getParameter("body"); ResultMsg resultMsg = new ResultMsg(); try{ boolean flag = udunClient.checkSign(timestamp, nonce, body, sign); log.info("===withdrawCallback===sign:{}", flag); if (!flag){ resultMsg.setCode(406); resultMsg.setMessage("提现回调验签失败"); return resultMsg; } ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> map = objectMapper.readValue(body, HashMap.class); String address = map.get("address").toString(); String order_no = map.get("businessId").toString(); Withdraw withdraw = withdrawService.getOne(new LambdaQueryWrapper<>(Withdraw.class) .eq(Withdraw::getOrderNo, order_no).last(" limit 1 ")); if(ObjectUtil.isEmpty(withdraw) && withdraw.getStatus() != 0 && !withdraw.getAddress().equals(address)){ log.info("withdraw failed:{}", withdraw); resultMsg.setCode(200); return resultMsg; } withdrawService.examineOk(order_no, Long.valueOf(withdraw.getUserId())); resultMsg.setCode(200); }catch (Exception e){ resultMsg.setCode(500); resultMsg.setMessage("回调处理失败"); } return resultMsg; } /** * 提现订单详情 trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java
@@ -9,6 +9,7 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.fasterxml.jackson.databind.ObjectMapper; import com.yami.trading.bean.vo.RechargeAddressVo; import com.yami.trading.security.common.enums.CryptoCurrencyEnum; import com.yami.trading.security.common.util.LocalKeyStorageAESUtil; import com.yami.trading.api.UD.*; @@ -36,6 +37,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -66,13 +68,8 @@ private SysUserService sysUserService; @Autowired RechargeBlockchainOrderService rechargeBlockchainOrderService; private final String gateway = "https://sig11.udun.io"; private final String merchantKey = "7fd79e4ed59e7c31e1fa2e13d64f7e6c"; private final String merchantId = "319563"; private final String defaultCallBackUrl = "https://openapi.yanshiz.com/api/channelBlockchain!rechargeCallback.action"; @Autowired UdunClient udunClient; /** * 获取所有链地址 @@ -123,9 +120,8 @@ */ @GetMapping(action + "getBlockchainName.action") public Object getBlockchainName(HttpServletRequest request) throws Exception { String coin = request.getParameter("coin"); List<ChannelBlockchain> data = new ArrayList<ChannelBlockchain>(); /*String coin = request.getParameter("coin"); List<ChannelBlockchain> data = new ArrayList<>(); try { coin = coin.toLowerCase(); Map<String, List<CryptoCurrencyEnum>> allGroupedByCoin = CryptoCurrencyEnum.getAllGroupedByCoin(); @@ -148,11 +144,8 @@ log.error("获取充值地址错误:",e); return Result.failed("充值链暂不可用"); } return Result.succeed(data); return Result.succeed(data);*/ // String partyId =SecurityUtils.getUser().getUserId(); // User party = userService.getById(partyId); // if (0 == this.sysparaService.find("can_recharge").getInteger()) { // return Result.failed("请联系客服充值"); @@ -202,92 +195,65 @@ // if (0 == this.sysparaService.find("can_recharge").getInteger()) { // return Result.failed("请联系客服充值"); // } // RechargeAddressVo rechargeAddressVo = new RechargeAddressVo(); // // //获取u盾地址 // //获取商户支持币种 // List<Coin> coinList = listSupportCoin(merchantId,false); // //创建地址 // coinList.forEach(f->{ // Address address = new Address(); // if(f.getName().equals("BTC")){ // String ress = (String)redisTemplate.opsForValue().get(partyId + "BTC"); // if(StringUtils.isNotEmpty(ress)){ // rechargeAddressVo.setAddress(ress); // rechargeAddressVo.setCoin(coin); // rechargeAddressVo.setBlockchainName(coin); // }else{ // address = createAddress(f.getMainCoinType(),null,null,null); // rechargeAddressVo.setAddress(address.getAddress()); // rechargeAddressVo.setCoin(coin); // rechargeAddressVo.setBlockchainName(coin); // redisTemplate.opsForValue().set(partyId + "BTC",address.getAddress()); // } // }else if(f.getName().equals("ETH")){ // String ress = (String)redisTemplate.opsForValue().get(partyId + "ETH"); // if(StringUtils.isNotEmpty(ress)){ // rechargeAddressVo.setAddress(ress); // rechargeAddressVo.setCoin(coin); // rechargeAddressVo.setBlockchainName(coin); // }else{ // address = createAddress(f.getMainCoinType(),null,null,null); // rechargeAddressVo.setAddress(address.getAddress()); // rechargeAddressVo.setCoin(coin); // rechargeAddressVo.setBlockchainName(coin); // redisTemplate.opsForValue().set(partyId + "ETH",address.getAddress()); // } // }else if(f.getName().equals("USDT")){ // String ress = (String)redisTemplate.opsForValue().get(partyId + "USDT"); // if(StringUtils.isNotEmpty(ress)){ // rechargeAddressVo.setAddress(ress); // rechargeAddressVo.setCoin(coin); // rechargeAddressVo.setBlockchainName(coin); // }else{ // address = createAddress(f.getMainCoinType(),null,null,null); // rechargeAddressVo.setAddress(address.getAddress()); // rechargeAddressVo.setCoin(coin); // rechargeAddressVo.setBlockchainName(coin); // redisTemplate.opsForValue().set(partyId + "USDT",address.getAddress()); // } // } // }); // return Result.succeed(rechargeAddressVo); String coin = request.getParameter("coin"); coin = coin.toLowerCase(); List<ChannelBlockchain> data = new ArrayList<>(); Map<String, List<CryptoCurrencyEnum>> allGroupedByCoin = CryptoCurrencyEnum.getAllGroupedByCoin(); List<CryptoCurrencyEnum> currencyEnums = allGroupedByCoin.get(coin); try { String partyId = SecurityUtils.getUser().getUserId(); //获取u盾地址 //获取商户支持币种 List<Coin> coinList = udunClient.listSupportCoin(false); currencyEnums.forEach((currencyEnum) -> { String coinName = currencyEnum.getName(); Coin c = coinList.stream().filter(x -> x.getName().equals(coinName)).findFirst().orElse(null); if (c != null) { ChannelBlockchain rechargeAddressVo = new ChannelBlockchain(); //创建地址 Address address; String ress = (String)redisTemplate.opsForValue().get(partyId + coinName); if(StringUtils.isNotEmpty(ress)){ rechargeAddressVo.setAddress(ress); }else{ address = udunClient.createAddress(c.getMainCoinType()); rechargeAddressVo.setAddress(address.getAddress()); redisTemplate.opsForValue().set(partyId + coinName, address.getAddress()); } //rechargeAddressVo.setAddress("test" + coinName); rechargeAddressVo.setCoin(currencyEnum.getCoin()); rechargeAddressVo.setBlockchain_name(currencyEnum.getChain()); rechargeAddressVo.setAuto(false); rechargeAddressVo.setImg(null); data.add(rechargeAddressVo); } }); }catch (Exception e){ log.error("获取充值地址错误:",e); return Result.failed("充值链暂不可用"); } return Result.succeed(data); } public List<Coin> listSupportCoin(String merchantId , boolean showBalance) { Map<String, Object> params = new HashMap<>(); params.put("merchantId", merchantId); params.put("showBalance", showBalance); ResultMsg result = JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.SUPPORT_COIN, JSONUtil.toJsonStr(params)), ResultMsg.class); if (result.getCode() != HttpStatus.HTTP_OK) { Console.error(JSONUtil.toJsonStr(result)); return null; } return JSONUtil.toList(JSONUtil.parseArray(result.getData()), Coin.class); } public Address createAddress(String mainCoinType, String alias, String walletId, String callUrl) throws UdunException { Map<String, String> params = new HashMap<>(); params.put("merchantId", merchantId); params.put("coinType", mainCoinType); params.put("callUrl", defaultCallBackUrl); params.put("walletId", walletId); params.put("alias", alias); ResultMsg result = JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.CREATE_ADDRESS, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class); if (result.getCode() != HttpStatus.HTTP_OK) { throw new UdunException(result.getCode(), result.getMessage()); } return JSONUtil.toBean(result.getData(), Address.class); } @RequestMapping(action +"rechargeCallback.action") @PostMapping(action +"rechargeCallback.action") public ResultMsg rechargeCallback(HttpServletRequest request){ String timestamp = request.getParameter("timestamp"); String nonce = request.getParameter("nonce"); String sign = request.getParameter("sign"); String body = request.getParameter("body"); ResultMsg resultMsg = new ResultMsg(); try{ boolean flag = udunClient.checkSign(timestamp, nonce, body, sign); log.info("===rechargeCallback===sign:{}", flag); if (!flag){ resultMsg.setCode(406); resultMsg.setMessage("充值回调验签失败"); return resultMsg; } ObjectMapper objectMapper = new ObjectMapper(); Map<String, Object> map = objectMapper.readValue(body, HashMap.class); double amounts = Double.parseDouble(map.get("amount").toString()); // 假设 amount 的值为 1000 @@ -295,22 +261,18 @@ double success_amount = amounts / Math.pow(10, decimals); String address = map.get("address").toString(); RechargeBlockchainOrder blockchainOrder = rechargeBlockchainOrderService.getOne(new LambdaQueryWrapper<>(RechargeBlockchainOrder.class) .eq(RechargeBlockchainOrder::getSucceeded, 0) .eq(RechargeBlockchainOrder::getChannelAddress, address).last(" limit 1 ")); if(ObjectUtil.isEmpty(blockchainOrder)){ ResultMsg resultMsg = new ResultMsg(); resultMsg.setCode(200); return resultMsg; } SysUser user = sysUserService.getSysUserById( Long.getLong(blockchainOrder.getPartyId())); rechargeBlockchainOrderService.manualReceipt(1,blockchainOrder.getPartyId(), BigDecimal.valueOf(success_amount),user.getUsername()); ResultMsg resultMsg = new ResultMsg(); resultMsg.setCode(200); return resultMsg; }catch (Exception e){ ResultMsg resultMsg = new ResultMsg(); resultMsg.setCode(500); resultMsg.setMessage("回调处理失败"); return resultMsg; trading-order-admin/src/main/resources/config/system.properties
@@ -1,5 +1,5 @@ http.server.host=http://127.0.0.1:8080/images/ images.dir=/mydata/img/ images.dir=/www/wwwroot/8.20/img/qr/ admin_url=https://127.0.0.1:8080/admin web_url=http://127.0.0.1:8080/wap/ trading-order-security-common/src/main/java/com/yami/trading/security/common/enums/CryptoCurrencyEnum.java
@@ -11,13 +11,20 @@ * @create: 2025-08-06 16:05 **/ public enum CryptoCurrencyEnum { USDT_TRC20("usdt", "TRC20","usdt_trc20"), /*USDT_TRC20("usdt", "TRC20","usdt_trc20"), USDT_ERC20("usdt", "ERC20","usdt_erc20"), ETH("eth", "ETH","eth"), BTC("btc", "BTC","btc"), USDC_ERC20("usdc", "ERC20(1)","usdc_erc20(1)"), USDC_ERC202("usdc", "ERC20(2)","usdc_erc20(2)"), USDC_TRC20("usdc", "TRC20","usdc_trc20"); USDC_TRC20("usdc", "TRC20","usdc_trc20");*/ USDT_TRC20("usdt", "TRC20","USDT-TRC20"), USDT_ERC20("usdt", "ERC20","USDT-ERC20"), ETH("eth", "ETH","ETH"), BTC("btc", "BTC","BTC"), USDC_ERC20("usdc", "ERC20","USDC-ERC20"), USDC_TRC20("usdc", "TRC20","USDC-TRC20"); private final String coin; trading-order-service/src/main/java/com/yami/trading/service/impl/WithdrawServiceImpl.java
@@ -95,6 +95,8 @@ symbol = "btc"; } else if (withdraw.getMethod().indexOf("ETH") != -1) { symbol = "eth"; } else if (withdraw.getMethod().indexOf("USDC") != -1) { symbol = "usdc"; } else { symbol = "usdt"; } @@ -436,6 +438,9 @@ } else if (channel.indexOf("ETH") != -1) { saveApplyOtherChannel(withdraw, "ethusdt"); return; } else if (channel.indexOf("USDC") != -1) { saveApplyOtherChannel(withdraw, "usdcusdt"); return; } User party = userService.getById(withdraw.getUserId()); if (Constants.SECURITY_ROLE_TEST.equals(party.getRoleName())) {