11 files modified
	
		
		4 files added
	
	
 
	
	
	
	
	
	
	
	
 |  |  | 
 |  |  |  | 
 |  |  |     public static final String EXCHANGE_A = "biue-exchange-A"; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public static final String EXCHANGE_USDT_UPDATE = "exchange_usdt_update"; | 
 |  |  |  | 
 |  |  |     public static final String QUEUE_USDT_UPDATE = "queue_usdt_update"; | 
 |  |  |  | 
 |  |  |     public static final String ROUTING_KEY_USDT_UPDATE = "routing_key_usdt_update"; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 撮合交易 | 
 |  |  |      */ | 
 |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |    @Bean | 
 |  |  |     public DirectExchange usdtUpdateExchange() { | 
 |  |  |         return new DirectExchange(EXCHANGE_USDT_UPDATE); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     @Bean | 
 |  |  |     public Queue usdtUpdateQueue() { | 
 |  |  |         return new Queue(QUEUE_USDT_UPDATE, true); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Bean | 
 |  |  |     public Binding usdtUpdatebinding() { | 
 |  |  |         return BindingBuilder.bind(usdtUpdateQueue()).to(usdtUpdateExchange()).with(ROUTING_KEY_USDT_UPDATE); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 交换器A 可以继续添加交换器B C | 
 |  |  |      * | 
 
| New file | 
 |  |  | 
 |  |  | package com.xcong.excoin.modules.blackchain.model; | 
 |  |  |  | 
 |  |  | import lombok.Data; | 
 |  |  |  | 
 |  |  | import java.math.BigDecimal; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  *  充值扫块dto | 
 |  |  |  */ | 
 |  |  | @Data | 
 |  |  | public class EthUsdtChargeDto { | 
 |  |  |  | 
 |  |  |     private String address; | 
 |  |  |     private String hash; | 
 |  |  |     private BigDecimal balance; | 
 |  |  |  | 
 |  |  |     public EthUsdtChargeDto() { | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public EthUsdtChargeDto(String address, String hash, BigDecimal balance) { | 
 |  |  |         this.address = address; | 
 |  |  |         this.hash = hash; | 
 |  |  |         this.balance = balance; | 
 |  |  |     } | 
 |  |  | } | 
 
 |  |  | 
 |  |  |                                 coinAddress.setLabel(uuid);
 | 
 |  |  |                                 memberMapper.insert(coinAddress);
 | 
 |  |  |                             }
 | 
 |  |  |                             if(!UsdtErc20UpdateService.ALL_ADDRESS_LIST.contains(address)){
 | 
 |  |  |                                 UsdtErc20UpdateService.ALL_ADDRESS_LIST.add(address);
 | 
 |  |  |                             }
 | 
 |  |  |                         }
 | 
 |  |  |                         break;
 | 
 |  |  |                     case "ROC":
 | 
 
 |  |  | 
 |  |  | package com.xcong.excoin.modules.blackchain.service; | 
 |  |  |  | 
 |  |  | import com.alibaba.fastjson.JSONObject; | 
 |  |  | import com.xcong.excoin.common.enumerates.CoinTypeEnum; | 
 |  |  | import com.xcong.excoin.modules.blackchain.model.EthUsdtChargeDto; | 
 |  |  | import com.xcong.excoin.modules.member.dao.MemberCoinAddressDao; | 
 |  |  | import com.xcong.excoin.rabbit.producer.UsdtUpdateProducer; | 
 |  |  | import com.xcong.excoin.utils.RedisUtils; | 
 |  |  | import org.apache.commons.lang.StringUtils; | 
 |  |  | import org.springframework.stereotype.Service; | 
 |  |  | import org.web3j.crypto.Credentials; | 
 |  |  | import org.web3j.protocol.Web3j; | 
 |  |  | 
 |  |  |  | 
 |  |  | @Service | 
 |  |  | public class UsdtErc20UpdateService { | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private UsdtUpdateProducer usdtUpdateProducer; | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private MemberCoinAddressDao  coinWalletDao; | 
 |  |  |  | 
 |  |  |     public final static List<String> ALL_ADDRESS_LIST = new ArrayList<>(); | 
 |  |  |  | 
 |  |  |     public final static String USDT_BLOCK_NUM = "USDT_BLOCK_NUM"; | 
 |  |  |     public final static String USDT_BLOCK_NUM_GOLDEN = "USDT_BLOCK_NUM_GOLDEN"; | 
 |  |  |  | 
 |  |  |     private final static BigInteger DIVIDE_USDT = new BigInteger("1000000"); | 
 |  |  |     private final static BigDecimal DIVIDE_USDT = new BigDecimal("1000000"); | 
 |  |  |  | 
 |  |  |     private static Web3j web3; | 
 |  |  |  | 
 |  |  | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private RedisUtils redisUtils; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     public void updateUsdt(){ | 
 |  |  |         // 首先查询所有的钱包地址 | 
 |  |  |         List<String> tdCoinWallets = coinWalletDao.selectAllSymbolAddress(CoinTypeEnum.USDT.toString(),"ERC20"); | 
 |  |  |         if(tdCoinWallets!=null){ | 
 |  |  |             ALL_ADDRESS_LIST.addAll(tdCoinWallets); | 
 |  |  |         } | 
 |  |  |         // 获取最新区块 | 
 |  |  |         String string = redisUtils.getString(USDT_BLOCK_NUM); | 
 |  |  |         String string = redisUtils.getString(USDT_BLOCK_NUM_GOLDEN); | 
 |  |  |         if(string==null){ | 
 |  |  |             string = "11014249"; | 
 |  |  |         } | 
 |  |  |         BigInteger blockNum = new BigInteger(string); | 
 |  |  |         Credentials credentials = Credentials.create(privateKey); | 
 |  |  |         EthUsdtContract contract = EthUsdtContract.load(contractAddr, web3, credentials, getStaticGasProvider()); | 
 |  |  |         EthFilter filter = getFilter(new BigInteger("10943021")); | 
 |  |  |         EthUsdtContract contract = EthUsdtContract.load(contractAddr, getInstance(), credentials, getStaticGasProvider()); | 
 |  |  |         EthFilter filter = getFilter(blockNum); | 
 |  |  |         contract.transferEventFlowable(filter).subscribe(e->{ | 
 |  |  |             if(e!=null){ | 
 |  |  |             if(e!=null && StringUtils.isNotBlank(e.to)){ | 
 |  |  |                 String transactionHash = e.log.getTransactionHash(); | 
 |  |  |                 BigInteger blockNumber1 = e.log.getBlockNumber(); | 
 |  |  |                 String toAddress = e.to; | 
 |  |  |                 BigInteger tokenBalance = e.tokens; | 
 |  |  |                 if(ALL_ADDRESS_LIST.contains(toAddress)){ | 
 |  |  |                     System.out.println("存在本地的地址:"+toAddress); | 
 |  |  |                 // 金额 | 
 |  |  |                 BigInteger divide = tokenBalance.divide(DIVIDE_USDT); | 
 |  |  |                 // 发送消息队列 TODO | 
 |  |  |                     BigDecimal divide = new BigDecimal(tokenBalance.toString()).divide(DIVIDE_USDT); | 
 |  |  |                     // 发送消息队列 | 
 |  |  |                     EthUsdtChargeDto dto = new EthUsdtChargeDto(toAddress,transactionHash,divide); | 
 |  |  |                     usdtUpdateProducer.sendMsg(JSONObject.toJSONString(dto)); | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 redisUtils.set(USDT_BLOCK_NUM_GOLDEN,blockNumber1.toString()); | 
 |  |  |             } | 
 |  |  |         }); | 
 |  |  |  | 
 |  |  | 
 |  |  |             return new EthFilter(DefaultBlockParameterName.EARLIEST, | 
 |  |  |                     DefaultBlockParameterName.LATEST, contractAddr); | 
 |  |  |         } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  | } | 
 
 |  |  | 
 |  |  | package com.xcong.excoin.modules.coin.service; | 
 |  |  |  | 
 |  |  | import com.xcong.excoin.modules.blackchain.model.EthUsdtChargeDto; | 
 |  |  | import com.xcong.excoin.modules.blackchain.model.RocTransferDetail; | 
 |  |  |  | 
 |  |  | public interface BlockCoinService { | 
 |  |  | 
 |  |  |  | 
 |  |  |     public void updateRoc(RocTransferDetail transferDetail); | 
 |  |  |  | 
 |  |  |     void updateEthUsdtNew(EthUsdtChargeDto ethUsdtChargeDto); | 
 |  |  |  | 
 |  |  | } | 
 
 |  |  | 
 |  |  |  | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public void updateEthUsdtNew(EthUsdtChargeDto ethUsdtChargeDto) { | 
 |  |  |         String address = ethUsdtChargeDto.getAddress(); | 
 |  |  |         String hash = ethUsdtChargeDto.getHash(); | 
 |  |  |         // hash没有用过 | 
 |  |  |         Map<String,Object> param = new HashMap<>(); | 
 |  |  |         param.put("hash",hash); | 
 |  |  |         param.put("address",address); | 
 |  |  |         List<MemberCoinChargeEntity> memberCoinChargeEntities = memberCoinChargeDao.selectByMap(param); | 
 |  |  |         if(CollectionUtils.isNotEmpty(memberCoinChargeEntities)){ | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |         MemberCoinAddressEntity coinAddressEntity = memberCoinAddressDao.selectBlockAddressWithTag(null, CoinTypeEnum.USDT.toString(), "ERC20"); | 
 |  |  |         if (coinAddressEntity == null) { | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |         Long memberId = coinAddressEntity.getMemberId(); | 
 |  |  |         BigDecimal balance = ethUsdtChargeDto.getBalance(); | 
 |  |  |         if (balance != null && balance.compareTo(new BigDecimal("0.1")) > 0) { | 
 |  |  |             balance = balance.setScale(8, RoundingMode.CEILING); | 
 |  |  |             BigDecimal early = BigDecimal.ZERO; | 
 |  |  |  | 
 |  |  |             MemberWalletCoinEntity walletCoinEntity = memberWalletCoinDao.selectWalletCoinBymIdAndCode(memberId, CoinTypeEnum.USDT.name()); | 
 |  |  |             if (walletCoinEntity == null) { | 
 |  |  |                 return; | 
 |  |  |             } | 
 |  |  |             BigDecimal newBalance = balance.subtract(early); | 
 |  |  |             memberWalletCoinDao.updateBlockBalance(walletCoinEntity.getId(), newBalance, balance, 0); | 
 |  |  |             String orderNo = insertCoinCharge(address, memberId, newBalance, CoinTypeEnum.USDT.name(), "ERC20", balance, ethUsdtChargeDto.getHash()); | 
 |  |  |             // 插入财务记录 | 
 |  |  |             LogRecordUtils.insertMemberAccountMoneyChange(memberId, "转入", newBalance, CoinTypeEnum.USDT.name(), 1, 1); | 
 |  |  |             ThreadPoolUtils.sendDingTalk(5); | 
 |  |  |             MemberEntity member = memberDao.selectById(memberId); | 
 |  |  |             if (StrUtil.isNotBlank(member.getPhone())) { | 
 |  |  |                 String amount = newBalance.toPlainString() + "USDT-ERC20"; | 
 |  |  |                 Sms106Send.sendRechargeMsg(member.getPhone(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo); | 
 |  |  |             } else { | 
 |  |  |                 SubMailSend.sendRechargeMail(member.getEmail(), DateUtil.format(new Date(), DatePattern.NORM_DATETIME_MINUTE_PATTERN), orderNo); | 
 |  |  |             } | 
 |  |  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private String generateNo() { | 
 |  |  |         // 生成订单号 | 
 |  |  |         Long timestamp = System.currentTimeMillis(); | 
 
 |  |  | 
 |  |  | 
 | 
 |  |  |     List<MemberCoinAddressEntity> selectAllBlockAddressBySymbol(@Param("symbol") String symbol);
 | 
 |  |  | 
 | 
 |  |  |     List<String> selectAllSymbolAddress(@Param("symbol")String symbol,@Param("tag") String tag);
 | 
 |  |  | 
 | 
 |  |  | }
 | 
 
 |  |  | 
 |  |  |  | 
 |  |  |         // 存储昨日K线 | 
 |  |  |         if("day".equals(rangeUnit)){ | 
 |  |  |             System.out.println("存储日K线"); | 
 |  |  |             redisUtils.set("ROC/USDT",kLine); | 
 |  |  |         } | 
 |  |  |     } | 
 
 |  |  | 
 |  |  |     /** | 
 |  |  |      * ETH_USDT 同步 | 
 |  |  |      */ | 
 |  |  |     @Scheduled(cron = "0 0/10 * * * ? ") | 
 |  |  |     public void ethUsdtUpdate() { | 
 |  |  |         blockCoinService.updateEthUsdt(); | 
 |  |  |     } | 
 |  |  |     //@Scheduled(cron = "0 0/10 * * * ? ") | 
 |  |  | //    public void ethUsdtUpdate() { | 
 |  |  | //        blockCoinService.updateEthUsdt(); | 
 |  |  | //    } | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * eth 同步 | 
 |  |  | 
 |  |  |     /** | 
 |  |  |      * BTC_USDT 同步 | 
 |  |  |      */ | 
 |  |  |     @Scheduled(cron = "0 2/10 * * * ? ") | 
 |  |  |     //@Scheduled(cron = "0 2/10 * * * ? ") | 
 |  |  |     public void btcUsdtUpdate() { | 
 |  |  |         blockCoinService.updateBtcUsdt(); | 
 |  |  |     } | 
 |  |  | 
 |  |  |     /** | 
 |  |  |      * ETH_USDT 同步 | 
 |  |  |      */ | 
 |  |  |     @Scheduled(cron = "0 0/5 * * * ? ") | 
 |  |  |     //Scheduled(cron = "0 0/5 * * * ? ") | 
 |  |  |     public void rocUpdate() { | 
 |  |  |         blockCoinService.updateEthUsdt(); | 
 |  |  |        // blockCoinService.updateEthUsdt(); | 
 |  |  |     } | 
 |  |  | } | 
 
 |  |  | 
 |  |  |     @Resource | 
 |  |  |     private CoinProcessorFactory processorFactory; | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private OrderCoinService orderCoinService; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     //@Scheduled(cron = "0/40 * * * * *") | 
 |  |  |     public void test(){ | 
 |  |  |         Random random = new Random(); | 
 |  |  |         Integer type = OrderCoinsDealEntity.ORDERTYPE_BUY; | 
 |  |  |         Integer tradeType = OrderCoinsDealEntity.TRADETYPE_FIXEDPRICE; | 
 |  |  |         double random1 = Math.random(); | 
 |  |  |         BigDecimal price = new BigDecimal(random1).setScale(4, RoundingMode.HALF_UP).multiply(new BigDecimal("2")); | 
 |  |  |         if(price.compareTo(BigDecimal.ZERO)==0){ | 
 |  |  |             price = BigDecimal.ONE; | 
 |  |  |         } | 
 |  |  |         System.out.println(price); | 
 |  |  |         orderCoinService.initOrders("ROC",type,tradeType,price,new BigDecimal(2),null); | 
 |  |  |         orderCoinService.initOrders("ROC",OrderCoinsDealEntity.ORDERTYPE_SELL,tradeType,price,new BigDecimal(2),null); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 每分钟定时器,处理分钟K线 | 
 
 |  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @Scheduled(cron = "0 2/8 * * * ? ") | 
 |  |  |     public void usdtEthPoolCheck() { | 
 |  |  |         log.info("USDTETH归集结果扫描开始"); | 
 |  |  |         usdtEthService.usdtEthPoolCheck(); | 
 |  |  |     } | 
 |  |  | //    @Scheduled(cron = "0 2/8 * * * ? ") | 
 |  |  | //    public void usdtEthPoolCheck() { | 
 |  |  | //        log.info("USDTETH归集结果扫描开始"); | 
 |  |  | //        usdtEthService.usdtEthPoolCheck(); | 
 |  |  | //    } | 
 |  |  |  | 
 |  |  |     @Scheduled(cron = "0 2/30 * * * ? ") | 
 |  |  |     public void poolEth() { | 
 
| New file | 
 |  |  | 
 |  |  | package com.xcong.excoin.quartz.job; | 
 |  |  |  | 
 |  |  | import com.xcong.excoin.modules.blackchain.service.UsdtErc20UpdateService; | 
 |  |  | import lombok.extern.slf4j.Slf4j; | 
 |  |  | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 
 |  |  | import org.springframework.stereotype.Component; | 
 |  |  |  | 
 |  |  | import javax.annotation.PostConstruct; | 
 |  |  | import javax.annotation.Resource; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  *  开启撮合交易 | 
 |  |  |  * | 
 |  |  |  * @author wzy | 
 |  |  |  * @date 2020-05-28 | 
 |  |  |  **/ | 
 |  |  | @Slf4j | 
 |  |  | @Component | 
 |  |  | @ConditionalOnProperty(prefix = "app", name = "block-job", havingValue = "true") | 
 |  |  | public class UsdtErc20InitJob { | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private UsdtErc20UpdateService usdtErc20UpdateService; | 
 |  |  |  | 
 |  |  |     @PostConstruct | 
 |  |  |     public void initCoinTrade() { | 
 |  |  |         System.out.println("开启USDT同步"); | 
 |  |  |         usdtErc20UpdateService.updateUsdt(); | 
 |  |  |     } | 
 |  |  | } | 
 
| New file | 
 |  |  | 
 |  |  | package com.xcong.excoin.rabbit.consumer; | 
 |  |  |  | 
 |  |  | import com.alibaba.fastjson.JSONObject; | 
 |  |  | import com.xcong.excoin.configurations.RabbitMqConfig; | 
 |  |  | import com.xcong.excoin.modules.blackchain.model.EthUsdtChargeDto; | 
 |  |  | import com.xcong.excoin.modules.coin.service.BlockCoinService; | 
 |  |  | import lombok.extern.slf4j.Slf4j; | 
 |  |  | import org.springframework.amqp.rabbit.annotation.RabbitListener; | 
 |  |  | import org.springframework.stereotype.Component; | 
 |  |  |  | 
 |  |  | import javax.annotation.Resource; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * @author wzy | 
 |  |  |  * @date 2020-05-25 | 
 |  |  |  **/ | 
 |  |  | @Slf4j | 
 |  |  | @Component | 
 |  |  | public class UsdtUpdateConsumer { | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private BlockCoinService blockCoinService; | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     @RabbitListener(queues = RabbitMqConfig.QUEUE_USDT_UPDATE) | 
 |  |  |     public void doSomething(String content) { | 
 |  |  |         log.info("#---->{}#", content); | 
 |  |  |         EthUsdtChargeDto ethUsdtChargeDto = JSONObject.parseObject(content, EthUsdtChargeDto.class); | 
 |  |  |         // 更新这个用户的余额 | 
 |  |  |         blockCoinService.updateEthUsdtNew(ethUsdtChargeDto); | 
 |  |  |     } | 
 |  |  | } | 
 
| New file | 
 |  |  | 
 |  |  | package com.xcong.excoin.rabbit.producer; | 
 |  |  |  | 
 |  |  | import cn.hutool.core.util.IdUtil; | 
 |  |  | import com.xcong.excoin.configurations.RabbitMqConfig; | 
 |  |  | import lombok.extern.slf4j.Slf4j; | 
 |  |  | import org.springframework.amqp.rabbit.connection.CorrelationData; | 
 |  |  | import org.springframework.amqp.rabbit.core.RabbitTemplate; | 
 |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
 |  |  | import org.springframework.stereotype.Component; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * @author wzy | 
 |  |  |  * @date 2020-05-25 | 
 |  |  |  **/ | 
 |  |  | @Slf4j | 
 |  |  | @Component | 
 |  |  | public class UsdtUpdateProducer implements RabbitTemplate.ConfirmCallback { | 
 |  |  |  | 
 |  |  |     private RabbitTemplate rabbitTemplate; | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     public UsdtUpdateProducer(RabbitTemplate rabbitTemplate) { | 
 |  |  |         this.rabbitTemplate = rabbitTemplate; | 
 |  |  |         rabbitTemplate.setConfirmCallback(this); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public void sendMsg(String content) { | 
 |  |  |         CorrelationData correlationData = new CorrelationData(IdUtil.simpleUUID()); | 
 |  |  |         rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE_USDT_UPDATE, RabbitMqConfig.ROUTING_KEY_USDT_UPDATE, content, correlationData); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public void confirm(CorrelationData correlationData, boolean ack, String cause) { | 
 |  |  |         log.info("#----->{}#", correlationData); | 
 |  |  |         if (ack) { | 
 |  |  |             log.info("success"); | 
 |  |  |         } else { | 
 |  |  |             log.info("--->{}", cause); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  | } | 
 
 |  |  | 
 |  |  |         select * from member_coin_address
 | 
 |  |  |         where symbol=#{symbol}
 | 
 |  |  |     </select>
 | 
 |  |  | 
 | 
 |  |  |     <select id="selectAllSymbolAddress" resultType="string" parameterType="map">
 | 
 |  |  |         select address from member_coin_address where symbol =#{symbol}
 | 
 |  |  |         <if test="tag!=null and tag !=''">
 | 
 |  |  |             and tag = #{tag}
 | 
 |  |  |         </if>
 | 
 |  |  |     </select>
 | 
 |  |  | </mapper> |