6 files modified
9 files added
| | |
| | | import cn.hutool.extra.qrcode.QrConfig; |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.fasterxml.jackson.databind.ObjectMapper; |
| | | import com.yami.trading.UD.*; |
| | | import com.yami.trading.UD.Address; |
| | | import com.yami.trading.bean.exchange.PartyBlockchain; |
| | | import com.yami.trading.bean.model.ChannelBlockchain; |
| | | import com.yami.trading.bean.model.RechargeBlockchainOrder; |
| | | import com.yami.trading.bean.model.User; |
| | | import com.yami.trading.common.constants.Constants; |
| | | import com.yami.trading.common.constants.RedisKeys; |
| | | import com.yami.trading.common.domain.Result; |
| | | import com.yami.trading.common.exception.YamiShopBindException; |
| | | import com.yami.trading.common.util.MD5; |
| | | import com.yami.trading.common.util.StringUtils; |
| | | import com.yami.trading.security.common.util.SecurityUtils; |
| | | import com.yami.trading.service.ChannelBlockchainService; |
| | | import com.yami.trading.service.RechargeBlockchainOrderService; |
| | | import com.yami.trading.service.exchange.PartyBlockchainService; |
| | | import com.yami.trading.service.syspara.SysparaService; |
| | | import com.yami.trading.service.user.UserService; |
| | | import io.swagger.annotations.Api; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import okhttp3.*; |
| | | import okhttp3.RequestBody; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.web.bind.annotation.CrossOrigin; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.data.redis.core.RedisTemplate; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.io.IOException; |
| | | import java.math.BigDecimal; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | UserService userService; |
| | | @Autowired |
| | | PartyBlockchainService partyBlockchainService; |
| | | |
| | | @Autowired |
| | | UdunClient udunClient; |
| | | |
| | | @Autowired |
| | | RedisTemplate redisTemplate; |
| | | |
| | | @Autowired |
| | | RechargeBlockchainOrderService rechargeBlockchainOrderService; |
| | | |
| | | /** |
| | | * 获取所有链地址 |
| | |
| | | * 根据币种获取链地址 |
| | | */ |
| | | @GetMapping(action + "getBlockchainName.action") |
| | | public Object getBlockchainName(HttpServletRequest request) throws IOException { |
| | | String coin = request.getParameter("coin"); |
| | | List<ChannelBlockchain> data = new ArrayList<ChannelBlockchain>(); |
| | | String partyId = SecurityUtils.getUser().getUserId(); |
| | | User party = userService.getById(partyId); |
| | | if (0 == this.sysparaService.find("can_recharge").getInteger()) { |
| | | return Result.failed("请联系客服充值"); |
| | | } |
| | | List<PartyBlockchain> list = partyBlockchainService.findByUserNameAndCoinSymbol(party.getUserName(), coin); |
| | | if (null != list && !list.isEmpty()) { |
| | | data = list.stream().map(dict -> { |
| | | String qrImage = dict.getQrImage(); |
| | | String chainAddress = dict.getAddress(); |
| | | String chainName = dict.getChainName(); |
| | | String coinSymbol = dict.getCoinSymbol(); |
| | | String autoStr = dict.getAuto(); |
| | | boolean auto = autoStr.equals("Y") ? true : false; |
| | | ChannelBlockchain cbc = new ChannelBlockchain(); |
| | | cbc.setBlockchain_name(chainName); |
| | | cbc.setAddress(chainAddress); |
| | | cbc.setCoin(coinSymbol); |
| | | cbc.setAuto(auto); |
| | | cbc.setImg(qrImage); |
| | | return cbc; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | if (data.isEmpty()) data = this.channelBlockchainService.findByCoin(coin.toLowerCase()); |
| | | for (int i = 0; i < data.size(); i++) { |
| | | data.get(i).setBlockchain_name(data.get(i).getBlockchainName()); |
| | | if (1 == this.sysparaService.find("can_recharge").getInteger()) { |
| | | if (!StringUtils.isNullOrEmpty(data.get(i).getImg())) { |
| | | QrConfig config = new QrConfig(150, 150); |
| | | config.setMargin(3); |
| | | String qr = QrCodeUtil.generateAsBase64(data.get(i).getAddress(), config, "png"); |
| | | data.get(i).setImgStr(qr); |
| | | // data.get(i).setImgStr("/public/showimg!showImg.action?imagePath=" + data.get(i).getImg()); |
| | | // data.get(i).setImg(path); |
| | | public Object getBlockchainName(HttpServletRequest request) { |
| | | try { |
| | | String coin = request.getParameter("coin"); |
| | | |
| | | String partyId = SecurityUtils.getUser().getUserId(); |
| | | if (coin.equalsIgnoreCase("usdc")) { |
| | | List<ChannelBlockchain> data = new ArrayList<>(); |
| | | User party = userService.getById(partyId); |
| | | if (0 == this.sysparaService.find("can_recharge").getInteger()) { |
| | | return Result.failed("请联系客服充值"); |
| | | } |
| | | List<PartyBlockchain> list = partyBlockchainService.findByUserNameAndCoinSymbol(party.getUserName(), coin); |
| | | if (null != list && !list.isEmpty()) { |
| | | data = list.stream().map(dict -> { |
| | | String qrImage = dict.getQrImage(); |
| | | String chainAddress = dict.getAddress(); |
| | | String chainName = dict.getChainName(); |
| | | String coinSymbol = dict.getCoinSymbol(); |
| | | String autoStr = dict.getAuto(); |
| | | boolean auto = autoStr.equals("Y") ? true : false; |
| | | ChannelBlockchain cbc = new ChannelBlockchain(); |
| | | cbc.setBlockchain_name(chainName); |
| | | cbc.setAddress(chainAddress); |
| | | cbc.setCoin(coinSymbol); |
| | | cbc.setAuto(auto); |
| | | cbc.setImg(qrImage); |
| | | return cbc; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | if (data.isEmpty()) data = this.channelBlockchainService.findByCoin(coin.toLowerCase()); |
| | | for (int i = 0; i < data.size(); i++) { |
| | | data.get(i).setBlockchain_name(data.get(i).getBlockchainName()); |
| | | if (1 == this.sysparaService.find("can_recharge").getInteger()) { |
| | | if (!StringUtils.isNullOrEmpty(data.get(i).getImg())) { |
| | | QrConfig config = new QrConfig(150, 150); |
| | | config.setMargin(3); |
| | | String qr = QrCodeUtil.generateAsBase64(data.get(i).getAddress(), config, "png"); |
| | | data.get(i).setImgStr(qr); |
| | | // data.get(i).setImgStr("/public/showimg!showImg.action?imagePath=" + data.get(i).getImg()); |
| | | // data.get(i).setImg(path); |
| | | } |
| | | } else { |
| | | data.get(i).setImg(null); |
| | | data.get(i).setImgStr(null); |
| | | data.get(i).setAddress(null); |
| | | } |
| | | } |
| | | return Result.succeed(data); |
| | | } else { |
| | | data.get(i).setImg(null); |
| | | data.get(i).setImgStr(null); |
| | | data.get(i).setAddress(null); |
| | | coin = coin.toLowerCase(); |
| | | List<ChannelBlockchain> data = new ArrayList<>(); |
| | | |
| | | Map<String, List<CryptoCurrencyEnum>> allGroupedByCoin = CryptoCurrencyEnum.getAllGroupedByCoin(); |
| | | List<CryptoCurrencyEnum> currencyEnums = allGroupedByCoin.get(coin); |
| | | 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(RedisKeys.BLOCKCHAIN_ADDRESS + partyId + coinName); |
| | | if(StringUtils.isNotEmpty(ress)){ |
| | | rechargeAddressVo.setAddress(ress); |
| | | }else{ |
| | | address = udunClient.createAddress(c.getMainCoinType()); |
| | | rechargeAddressVo.setAddress(address.getAddress()); |
| | | redisTemplate.opsForValue().set(RedisKeys.BLOCKCHAIN_ADDRESS + partyId + coinName, address.getAddress()); |
| | | } |
| | | //rechargeAddressVo.setAddress("test" + coinName); |
| | | rechargeAddressVo.setCoin(currencyEnum.getCoin()); |
| | | rechargeAddressVo.setBlockchain_name(currencyEnum.getChain()); |
| | | rechargeAddressVo.setAuto(false); |
| | | rechargeAddressVo.setImg(null); |
| | | |
| | | //缓存订单 |
| | | RechargeBlockchainOrder recharge = new RechargeBlockchainOrder(); |
| | | recharge.setBlockchainName(currencyEnum.getChain()); |
| | | recharge.setSymbol(currencyEnum.getSymbol()); |
| | | recharge.setPartyId(partyId); |
| | | redisTemplate.opsForValue().set(rechargeAddressVo.getAddress(), recharge); |
| | | |
| | | data.add(rechargeAddressVo); |
| | | } |
| | | }); |
| | | return Result.succeed(data); |
| | | } |
| | | }catch (Exception e){ |
| | | log.error("获取充值地址错误:",e); |
| | | return Result.failed("失败"); |
| | | } |
| | | return Result.succeed(data); |
| | | } |
| | | |
| | | @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{ |
| | | log.info("===rechargeCallback===:{}", body); |
| | | 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 |
| | | double decimals = Double.parseDouble(map.get("decimals").toString()); |
| | | double success_amount = amounts / Math.pow(10, decimals); |
| | | String address = map.get("address").toString(); |
| | | Integer status = Integer.valueOf(map.get("status").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.setCode(200); |
| | | return resultMsg; |
| | | }*/ |
| | | |
| | | //查询地址订单 |
| | | RechargeBlockchainOrder blockchainOrder = (RechargeBlockchainOrder)redisTemplate.opsForValue().get(address); |
| | | if (blockchainOrder == null){ |
| | | resultMsg.setCode(200); |
| | | return resultMsg; |
| | | } |
| | | blockchainOrder.setAddress(null); |
| | | blockchainOrder.setVolume(success_amount); |
| | | blockchainOrder.setImg(null); |
| | | blockchainOrder.setSucceeded(0); |
| | | blockchainOrder.setChannelAddress(address); |
| | | blockchainOrder.setTx(""); |
| | | rechargeBlockchainOrderService.saveOrder(blockchainOrder); |
| | | User user = userService.getById(blockchainOrder.getPartyId()); |
| | | |
| | | log.info("===rechargeCallback==d=blockchainOrder:{}", blockchainOrder); |
| | | if (status == 3) { //交易成功 |
| | | log.info("===rechargeCallback==manualReceipt{}", blockchainOrder.getOrderNo()); |
| | | rechargeBlockchainOrderService.manualReceipt(blockchainOrder.getOrderNo(), BigDecimal.valueOf(success_amount), user.getUserName()); |
| | | } else if(status == 2) { //驳回 |
| | | rechargeBlockchainOrderService.refusalApply(blockchainOrder.getUuid(), "订单失败:" + status, user.getUserName()); |
| | | } |
| | | resultMsg.setCode(200); |
| | | return resultMsg; |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | resultMsg.setCode(500); |
| | | resultMsg.setMessage("回调处理失败"); |
| | | return resultMsg; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | admin_url: https://localhost:8080/admin |
| | | web_url: http://localhost:8080/wap/ |
| | | images_http: https://allimg.sc-easy.com/ |
| | | api_http: https://allapi.sceazy.com/ |
| | | |
| | | email: |
| | | host: smtp.gmail.com |
| | | username: coinzne.com@gmail.com |
| | |
| | | |
| | | public static final String IMAGES_HTTP = ApplicationUtil.getProperty("images_http"); |
| | | |
| | | public static final String API_HTTP = ApplicationUtil.getProperty("api_http"); |
| | | |
| | | |
| | | /** |
| | | * 质押2.0下单 |
| | | */ |
| | |
| | | * 区块链充值订单 |
| | | */ |
| | | public final static String RECHARGE_BLOCKCHAIN_ORDERNO = "RECHARGE_BLOCKCHAIN_ORDERNO_"; |
| | | |
| | | /** |
| | | * 充值地址缓存 |
| | | */ |
| | | public final static String BLOCKCHAIN_ADDRESS = "BLOCKCHAIN_ADDRESS"; |
| | | /** |
| | | * 提现订单 |
| | | */ |
| | |
| | | "/api/newOnlinechat**", |
| | | "/api/exchangerateuserconfig!get.action", |
| | | "/api/exchangerateuserconfig!getList.action", |
| | | "/api/channelBlockchain!rechargeCallback.action", |
| | | "/api/item/itemUserOptionalList/isItemHasAddGlobal", |
| | | "/api/item/itemUserOptionalList/list", |
| | | "/api/wallet/getUsdt", |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | |
| | | public class Address { |
| | | private String address; |
| | | private int coinType; |
| | | |
| | | public String getAddress() { |
| | | return address; |
| | | } |
| | | |
| | | public void setAddress(String address) { |
| | | this.address = address; |
| | | } |
| | | |
| | | public int getCoinType() { |
| | | return coinType; |
| | | } |
| | | |
| | | public void setCoinType(int coinType) { |
| | | this.coinType = coinType; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "Address{" + |
| | | "address='" + address + '\'' + |
| | | ", coinType=" + coinType + |
| | | '}'; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | public class ApiPath { |
| | | public final static String CREATE_ADDRESS = "/mch/address/create"; |
| | | public final static String WITHDRAW = "/mch/withdraw"; |
| | | public final static String TRANSACTION = "/mch/transaction"; |
| | | public final static String AUTO_WITHDRAW = "/mch/withdraw/proxypay"; |
| | | public final static String SUPPORT_COIN = "/mch/support-coins"; |
| | | public final static String CHECK_PROXY = "/mch/check-proxy"; |
| | | public final static String CHECK_ADDRESS = "/mch/check/address"; |
| | | public final static String CREATE_BATCH_ADDRESS = "/mch/address/create/batch"; |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | public class Coin { |
| | | private String name; |
| | | private String symbol; |
| | | private String mainCoinType; |
| | | private String coinType; |
| | | private String decimals; |
| | | private Integer tokenStatus; |
| | | private String mainSymbol; |
| | | private BigDecimal balance; |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | public void setName(String name) { |
| | | this.name = name; |
| | | } |
| | | |
| | | public String getSymbol() { |
| | | return symbol; |
| | | } |
| | | |
| | | public void setSymbol(String symbol) { |
| | | this.symbol = symbol; |
| | | } |
| | | |
| | | public String getMainCoinType() { |
| | | return mainCoinType; |
| | | } |
| | | |
| | | public void setMainCoinType(String mainCoinType) { |
| | | this.mainCoinType = mainCoinType; |
| | | } |
| | | |
| | | public String getCoinType() { |
| | | return coinType; |
| | | } |
| | | |
| | | public void setCoinType(String coinType) { |
| | | this.coinType = coinType; |
| | | } |
| | | |
| | | public String getDecimals() { |
| | | return decimals; |
| | | } |
| | | |
| | | public void setDecimals(String decimals) { |
| | | this.decimals = decimals; |
| | | } |
| | | |
| | | public Integer getTokenStatus() { |
| | | return tokenStatus; |
| | | } |
| | | |
| | | public void setTokenStatus(Integer tokenStatus) { |
| | | this.tokenStatus = tokenStatus; |
| | | } |
| | | |
| | | public String getMainSymbol() { |
| | | return mainSymbol; |
| | | } |
| | | |
| | | public void setMainSymbol(String mainSymbol) { |
| | | this.mainSymbol = mainSymbol; |
| | | } |
| | | |
| | | public BigDecimal getBalance() { |
| | | return balance; |
| | | } |
| | | |
| | | public void setBalance(BigDecimal balance) { |
| | | this.balance = balance; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @program: trading-order-master |
| | | * @description: 充值币种 |
| | | * @create: 2025-08-06 16:05 |
| | | **/ |
| | | public enum CryptoCurrencyEnum { |
| | | /*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");*/ |
| | | |
| | | USDT_TRC20("usdt", "TRC20","USDT-TRC20", "usdt"), |
| | | USDT_ERC20("usdt", "ERC20","USDT-ERC20", "usdt"), |
| | | ETH("eth", "ETH","ETH", "ethusdt"), |
| | | BTC("btc", "BTC","BTC", "btcusdt"), |
| | | USDC_ERC20("usdc", "ERC20","USDC-ERC20", "usdcusdt"), |
| | | USDC_TRC20("usdc", "TRC20","USDC-TRC20", "usdcusdt"); |
| | | |
| | | |
| | | private final String coin; |
| | | private final String chain; |
| | | private final String name; |
| | | private final String symbol; |
| | | |
| | | CryptoCurrencyEnum(String coin, String chain, String name, String symbol) { |
| | | this.coin = coin; |
| | | this.chain = chain; |
| | | this.name = name; |
| | | this.symbol = symbol; |
| | | } |
| | | |
| | | public String getSymbol() { |
| | | return symbol; |
| | | } |
| | | |
| | | public String getCoin() { |
| | | return coin; |
| | | } |
| | | |
| | | public String getChain() { |
| | | return chain; |
| | | } |
| | | |
| | | public String getName() { |
| | | return name; |
| | | } |
| | | |
| | | // 可选:根据代码获取枚举值的方法 |
| | | public static CryptoCurrencyEnum fromCoin(String coin,String chain) { |
| | | for (CryptoCurrencyEnum currency : values()) { |
| | | if (currency.getCoin().equals(coin) && currency.getChain().equals(chain)) { |
| | | return currency; |
| | | } |
| | | } |
| | | throw new IllegalArgumentException("没找到对应的币种: " + coin); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有枚举值(返回 List) |
| | | */ |
| | | public static List<CryptoCurrencyEnum> getAll() { |
| | | return Arrays.asList(values()); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有枚举值(按 coin 分组,返回 Map<String, List<CryptoCurrencyEnum>>) |
| | | */ |
| | | public static Map<String, List<CryptoCurrencyEnum>> getAllGroupedByCoin() { |
| | | return Arrays.stream(values()) |
| | | .collect(Collectors.groupingBy(CryptoCurrencyEnum::getCoin)); |
| | | } |
| | | |
| | | /** |
| | | * 获取所有枚举值(按 chain 分组,返回 Map<String, List<CryptoCurrencyEnum>>) |
| | | */ |
| | | public static Map<String, List<CryptoCurrencyEnum>> getAllGroupedByChain() { |
| | | return Arrays.stream(values()) |
| | | .collect(Collectors.groupingBy(CryptoCurrencyEnum::getChain)); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | public class ResultMsg { |
| | | private Integer code; |
| | | private String message; |
| | | private String data; |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(Integer code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | |
| | | public String getData() { |
| | | return data; |
| | | } |
| | | |
| | | public void setData(String data) { |
| | | this.data = data; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return "ResultMsg{" + |
| | | "code=" + code + |
| | | ", message='" + message + '\'' + |
| | | ", data='" + data + '\'' + |
| | | '}'; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | |
| | | public interface UdunApi { |
| | | /** |
| | | * 创建币种地址,别名和钱包编号默认,回调地址使用统一配置 |
| | | * |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @return 地址 |
| | | */ |
| | | Address createAddress(String mainCoinType) throws UdunException; |
| | | |
| | | /** |
| | | * 创建币种地址,别名和钱包编号自定义,回调地址使用统一配置 |
| | | * |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param alias 地址别名 |
| | | * @param walletId 钱包编号 |
| | | * @return 地址 |
| | | */ |
| | | Address createAddress(String mainCoinType, String alias, String walletId) throws UdunException; |
| | | |
| | | /** |
| | | * 创建币种地址,别名和钱包编号自定义,回调地址自定义 |
| | | * |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param alias 地址别名 |
| | | * @param walletId 钱包编号 |
| | | * @param callUrl 回调地址 |
| | | * @return 地址 |
| | | */ |
| | | Address createAddress(String mainCoinType, String alias, String walletId, String callUrl) throws UdunException; |
| | | |
| | | |
| | | /** |
| | | * 提币,回调地址使用统一配置 |
| | | * |
| | | * @param address 提币地址 |
| | | * @param amount 提币数量 |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param coinType 子币种编号,使用获取商户币种信息接口 |
| | | * @param businessId 业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收 |
| | | * @param memo 备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填 |
| | | * @return 返回信息 |
| | | */ |
| | | ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo); |
| | | |
| | | /** |
| | | * 提币,回调地址自定义 |
| | | * |
| | | * @param address 提币地址 |
| | | * @param amount 提币数量 |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param coinType 子币种编号,使用获取商户币种信息接口 |
| | | * @param businessId 业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收 |
| | | * @param memo 备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填 |
| | | * @param callUrl 回调地址 |
| | | * @return 返回信息 |
| | | */ |
| | | ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl); |
| | | |
| | | /** |
| | | * 代付,回调地址使用统一配置 |
| | | * |
| | | * @param address 提币地址 |
| | | * @param amount 提币数量 |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param coinType 子币种编号,使用获取商户币种信息接口 |
| | | * @param businessId 业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收 |
| | | * @param memo 备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填 |
| | | * @return 返回信息 |
| | | */ |
| | | ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo); |
| | | |
| | | /** |
| | | * 代付,回调地址自定义 |
| | | * |
| | | * @param address 提币地址 |
| | | * @param amount 提币数量 |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param coinType 子币种编号,使用获取商户币种信息接口 |
| | | * @param businessId 业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收 |
| | | * @param memo 备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填 |
| | | * @param callUrl 回调地址 |
| | | * @return 返回信息 |
| | | */ |
| | | ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl); |
| | | |
| | | /** |
| | | * 检验地址合法性 |
| | | * |
| | | * @param mainCoinType 主币种编号,使用获取商户币种信息接口 |
| | | * @param address 币种地址 |
| | | * @return 是否合法 |
| | | */ |
| | | boolean checkAddress(String mainCoinType, String address); |
| | | |
| | | /** |
| | | * 获取商户支持的币种,以及余额 |
| | | * |
| | | * @param showBalance 是否显示余额 |
| | | * @return 支持币种列表 |
| | | */ |
| | | List<Coin> listSupportCoin(boolean showBalance); |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | import cn.hutool.core.lang.Console; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import cn.hutool.http.HttpStatus; |
| | | import cn.hutool.json.JSONUtil; |
| | | import com.yami.trading.common.constants.Constants; |
| | | 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 = "https://sig11.udun.io"; |
| | | |
| | | /** |
| | | * UDUN Merchant Key |
| | | */ |
| | | private final String merchantKey = "cf6802e282476b74e2a3cfd16a6cf7ec"; |
| | | |
| | | /** |
| | | * UDUN Merchant Number |
| | | */ |
| | | private final String merchantId = "321912"; |
| | | |
| | | /** |
| | | * Callback 充值 |
| | | */ |
| | | private final String defaultCallBackUrl = Constants.API_HTTP + "api/channelBlockchain!rechargeCallback.action"; |
| | | |
| | | /** |
| | | * Callback 提币 |
| | | */ |
| | | private final String withdrawCallBackUrl = Constants.API_HTTP + "api/withdraw/withdrawCallback.action"; |
| | | |
| | | |
| | | |
| | | @Override |
| | | public Address createAddress(String mainCoinType) throws UdunException { |
| | | return createAddress(mainCoinType, "", "", defaultCallBackUrl); |
| | | } |
| | | |
| | | @Override |
| | | public Address createAddress(String mainCoinType, String alias, String walletId) throws UdunException{ |
| | | return createAddress(mainCoinType, alias, walletId, defaultCallBackUrl); |
| | | } |
| | | |
| | | @Override |
| | | 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("mainCoinType", mainCoinType); |
| | | params.put("callUrl", callUrl); |
| | | 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) { |
| | | logger.error("createAddress:{}",JSONUtil.toJsonStr(result)); |
| | | throw new UdunException(result.getCode(), result.getMessage()); |
| | | } |
| | | return JSONUtil.toBean(result.getData(), Address.class); |
| | | } |
| | | |
| | | @Override |
| | | public ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo) { |
| | | return withdraw(address, amount, mainCoinType, coinType, businessId, memo, withdrawCallBackUrl); |
| | | } |
| | | |
| | | @Override |
| | | public ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl) { |
| | | Map<String, Object> params = new HashMap<>(); |
| | | params.put("address", address); |
| | | params.put("amount", amount); |
| | | params.put("merchantId", merchantId); |
| | | params.put("mainCoinType", mainCoinType); |
| | | params.put("coinType", coinType); |
| | | params.put("callUrl", callUrl); |
| | | params.put("businessId", businessId); |
| | | params.put("memo", memo); |
| | | return JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.WITHDRAW, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class); |
| | | } |
| | | |
| | | @Override |
| | | public ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo) { |
| | | return autoWithdraw(address, amount, mainCoinType, coinType, businessId, memo, withdrawCallBackUrl); |
| | | } |
| | | |
| | | @Override |
| | | public ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl) { |
| | | Map<String, Object> params = new HashMap<>(); |
| | | params.put("address", address); |
| | | params.put("amount", amount); |
| | | params.put("merchantId", merchantId); |
| | | params.put("mainCoinType", mainCoinType); |
| | | params.put("coinType", coinType); |
| | | params.put("callUrl", callUrl); |
| | | params.put("businessId", businessId); |
| | | params.put("memo", memo); |
| | | return JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.AUTO_WITHDRAW, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class); |
| | | } |
| | | |
| | | @Override |
| | | public boolean checkAddress(String mainCoinType, String address) { |
| | | Map<String, String> params = new HashMap<>(); |
| | | params.put("merchantId", merchantId); |
| | | params.put("mainCoinType", mainCoinType); |
| | | params.put("address", address); |
| | | ResultMsg result = JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.CHECK_ADDRESS, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class); |
| | | return result.getCode() == HttpStatus.HTTP_OK; |
| | | } |
| | | |
| | | @Override |
| | | public List<Coin> listSupportCoin(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 boolean checkSign(String timestamp, String nonce, String body, String sign) { |
| | | String checkSign = UdunUtils.sign(merchantKey, timestamp, nonce, body); |
| | | return checkSign.equals(sign); |
| | | } |
| | | |
| | | public static void main(String[] args) { |
| | | Map<String, Object> params = new HashMap<>(); |
| | | params.put("merchantId", 321912); |
| | | params.put("showBalance", false); |
| | | ResultMsg result = JSONUtil.toBean(UdunUtils.post("https://sig11.udun.io", "cf6802e282476b74e2a3cfd16a6cf7ec", ApiPath.SUPPORT_COIN, JSONUtil.toJsonStr(params)), ResultMsg.class); |
| | | if (result.getCode() != HttpStatus.HTTP_OK) { |
| | | Console.error(JSONUtil.toJsonStr(result)); |
| | | } |
| | | List<Coin> coins = JSONUtil.toList(JSONUtil.parseArray(result.getData()), Coin.class); |
| | | System.out.println(coins); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | public class UdunException extends RuntimeException { |
| | | private Integer code; |
| | | private String message; |
| | | |
| | | public UdunException(Integer code, String message) { |
| | | this.code = code; |
| | | this.message = message; |
| | | } |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | |
| | | public void setCode(Integer code) { |
| | | this.code = code; |
| | | } |
| | | |
| | | @Override |
| | | public String getMessage() { |
| | | return message; |
| | | } |
| | | |
| | | public void setMessage(String message) { |
| | | this.message = message; |
| | | } |
| | | } |
| New file |
| | |
| | | package com.yami.trading.UD; |
| | | |
| | | import cn.hutool.core.util.RandomUtil; |
| | | import cn.hutool.crypto.SecureUtil; |
| | | import cn.hutool.json.JSONUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import java.io.BufferedReader; |
| | | import java.io.IOException; |
| | | import java.io.InputStreamReader; |
| | | import java.io.OutputStream; |
| | | import java.net.HttpURLConnection; |
| | | import java.net.URL; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | |
| | | public class UdunUtils { |
| | | private static Logger logger = LoggerFactory.getLogger(UdunUtils.class); |
| | | |
| | | public static String post(String gateway, String merchantKey, String path, String body) { |
| | | try { |
| | | // 创建 URL 对象 |
| | | URL url = new URL(gateway+path); |
| | | |
| | | // 打开连接 |
| | | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); |
| | | |
| | | // 设置请求方法为 POST |
| | | connection.setRequestMethod("POST"); |
| | | |
| | | // 设置请求头 |
| | | connection.setRequestProperty("Content-Type", "application/json"); |
| | | connection.setRequestProperty("Accept", "application/json"); |
| | | |
| | | // 启用输入输出流 |
| | | connection.setDoOutput(true); |
| | | |
| | | String rawBody = parseParams(merchantKey, body); |
| | | |
| | | // 写入请求体 |
| | | try (OutputStream os = connection.getOutputStream()) { |
| | | byte[] input = rawBody.getBytes("utf-8"); |
| | | os.write(input, 0, input.length); |
| | | } |
| | | |
| | | // 获取响应代码 |
| | | int responseCode = connection.getResponseCode(); |
| | | |
| | | // 读取响应 |
| | | try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { |
| | | String inputLine; |
| | | StringBuilder response = new StringBuilder(); |
| | | while ((inputLine = in.readLine()) != null) { |
| | | response.append(inputLine); |
| | | } |
| | | return response.toString(); |
| | | } |
| | | |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public static String parseParams(String merchantKey, String body) { |
| | | Map<String, String> params = new HashMap<>(); |
| | | String timestamp = System.currentTimeMillis() + ""; |
| | | String nonce = RandomUtil.randomString(6); |
| | | String sign = sign(merchantKey, timestamp, nonce, body); |
| | | params.put("timestamp", timestamp); |
| | | params.put("nonce", nonce); |
| | | params.put("sign", sign); |
| | | params.put("body", body); |
| | | return JSONUtil.toJsonStr(params); |
| | | } |
| | | |
| | | public static String sign(String key, String timestamp, String nonce, String body) { |
| | | String raw = body + key + nonce + timestamp; |
| | | return SecureUtil.md5(raw); |
| | | } |
| | | |
| | | } |
| | |
| | | // Date now = new Date(); |
| | | RechargeBlockchainOrder recharge = getById(id); |
| | | if (recharge == null) { |
| | | throw new YamiShopBindException("参数错误!"); |
| | | recharge = findByOrderNo(id); |
| | | if (recharge == null) { |
| | | throw new YamiShopBindException("参数错误!"); |
| | | } |
| | | } |
| | | User party = userService.getById(recharge.getPartyId()); |
| | | if (party == null) { |