package cc.mrbird.febs.dapp.service.impl; import cc.mrbird.febs.common.contants.AppContants; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; import cc.mrbird.febs.common.enumerates.DataDicEnum; import cc.mrbird.febs.common.enumerates.FlowTypeEnum; import cc.mrbird.febs.common.exception.FebsException; import cc.mrbird.febs.common.utils.LoginUserUtil; import cc.mrbird.febs.common.utils.RedisUtils; import cc.mrbird.febs.dapp.dto.*; import cc.mrbird.febs.dapp.entity.*; import cc.mrbird.febs.dapp.mapper.*; import cc.mrbird.febs.dapp.service.AsyncCjService; import cc.mrbird.febs.dapp.service.DappWalletService; import cc.mrbird.febs.dapp.vo.WalletInfoVo; import cc.mrbird.febs.rabbit.producer.ChainProducer; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.*; /** * @author * @date 2022-03-18 **/ @Slf4j @Service @RequiredArgsConstructor public class DappWalletServiceImpl implements DappWalletService { private final DappMemberDao dappMemberDao; private final DappWalletMineDao dappWalletMineDao; private final DappWalletCoinDao dappWalletCoinDao; private final DappFundFlowDao dappFundFlowDao; private final DappAccountMoneyChangeDao dappAccountMoneyChangeDao; private final RedisUtils redisUtils; private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final DappAchieveMapper dappAchieveMapper; private final DappAchieveItemMapper dappAchieveItemMapper; private final ChainProducer chainProducer; private final AsyncCjService asyncCjService; @Override public WalletInfoVo walletInfo() { Long memberId = LoginUserUtil.getAppUser().getId(); DappMemberEntity member = dappMemberDao.selectById(memberId); WalletInfoVo walletInfo = new WalletInfoVo(); walletInfo.setInviteId(member.getInviteId()); walletInfo.setBalance(member.getBalance()); walletInfo.setUsdtBalance(member.getUsdtBalance()); String zyOpen = redisUtils.getString(DataDicEnum.SYSTEM_START_FLAG.getValue()); walletInfo.setZyOpen(zyOpen.equals("start") ? 1 : 0); BigDecimal minAmount = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_BUY_MIN_AMOUNT.getValue())).setScale(2,BigDecimal.ROUND_DOWN); walletInfo.setZyMin(minAmount); BigDecimal maxAmount = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_BUY_MAX_AMOUNT.getValue())).setScale(2,BigDecimal.ROUND_DOWN); walletInfo.setZyMax(maxAmount); BigDecimal tzCoin = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.TUAN_DUI.getValue(),null); walletInfo.setTzCoin(tzCoin); BigDecimal hdCoinGeren = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.HUA_DIAN_GEREN.getValue(),null); BigDecimal hdCoinTuandui = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.HUA_DIAN_TUANDUI_DAIBI.getValue(),null); BigDecimal hdCoinTuanduiUSDT = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.HUA_DIAN_TUANDUI_USDT.getValue(),null); walletInfo.setHdCoin(hdCoinGeren.add(hdCoinTuandui).add(hdCoinTuanduiUSDT)); BigDecimal zyTotal = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.ZHI_YA.getValue(),null).negate(); walletInfo.setZyTotal(zyTotal); BigDecimal zyToday = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.ZHI_YA.getValue(), new Date()).negate(); walletInfo.setZyToday(zyToday); BigDecimal ccTotal = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.ZHIYA_CHA_CHU.getValue(),null).negate(); walletInfo.setCcTotal(ccTotal); BigDecimal ccToday = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDate(member.getId(), FlowTypeEnum.ZHIYA_CHA_CHU.getValue(), new Date()).negate(); walletInfo.setCcToday(ccToday); BigDecimal gfaDays = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_DAYS.getValue())).setScale(2,BigDecimal.ROUND_DOWN); walletInfo.setGfaDays(gfaDays); return walletInfo; } @Override @Transactional(rollbackFor = Exception.class) public void change(WalletOperateDto walletOperateDto) { DappMemberEntity member = LoginUserUtil.getAppUser(); BigDecimal ethUsdtPrice = (BigDecimal) redisUtils.get(AppContants.REDIS_KEY_ETH_NEW_PRICE); DappWalletMineEntity walletMine = dappWalletMineDao.selectByMemberId(member.getId()); if (walletOperateDto.getAmount().compareTo(walletMine.getAvailableAmount()) > 0) { throw new FebsException("可用金额不足"); } DappFundFlowEntity fund = new DappFundFlowEntity(member.getId(), walletOperateDto.getAmount(), AppContants.MONEY_TYPE_CHANGE, 2, (String) null); dappFundFlowDao.insert(fund); BigDecimal preEthAmount = walletMine.getAvailableAmount(); // TODO 并发加悲观锁 // 更新eth金额 walletMine.setAvailableAmount(walletMine.getAvailableAmount().subtract(walletOperateDto.getAmount())); dappWalletMineDao.updateById(walletMine); DappWalletCoinEntity walletCoin = dappWalletCoinDao.selectByMemberId(member.getId()); BigDecimal preUsdtAmount = walletCoin.getAvailableAmount(); // 更新usdt金额 BigDecimal usdt = walletOperateDto.getAmount().multiply(ethUsdtPrice); walletCoin.setAvailableAmount(walletCoin.getAvailableAmount().add(usdt)); walletCoin.setTotalAmount(walletCoin.getTotalAmount().add(usdt)); dappWalletCoinDao.updateById(walletCoin); DappAccountMoneyChangeEntity ethChange = new DappAccountMoneyChangeEntity(member.getId(), preEthAmount, walletOperateDto.getAmount(), walletMine.getAvailableAmount(), "ETH兑换USDT-ETH, 兑换价格为:" + ethUsdtPrice, AppContants.MONEY_TYPE_CHANGE); DappAccountMoneyChangeEntity usdtChange = new DappAccountMoneyChangeEntity(member.getId(), preUsdtAmount, usdt, walletCoin.getAvailableAmount(), "ETH兑换USDT-USDT, 兑换价格为:" + ethUsdtPrice, AppContants.MONEY_TYPE_CHANGE); dappAccountMoneyChangeDao.insert(ethChange); dappAccountMoneyChangeDao.insert(usdtChange); } @Override @Transactional(rollbackFor = Exception.class) public void withdraw(WalletOperateDto walletOperateDto) { DappMemberEntity member = LoginUserUtil.getAppUser(); List fundFlows = dappFundFlowDao.selectListForMemberAndDay(member.getId(), 2); if (CollUtil.isNotEmpty(fundFlows)) { throw new FebsException("一天只能提现一次"); } DappWalletCoinEntity walletCoin = dappWalletCoinDao.selectByMemberId(member.getId()); if (walletOperateDto.getAmount().compareTo(walletCoin.getAvailableAmount()) > 0) { throw new FebsException("可用金额不足"); } Integer fee = (Integer) redisUtils.get(AppContants.REDIS_KEY_CHANGE_FEE); //TODO 并发加悲观锁 BigDecimal preAmount = walletCoin.getAvailableAmount(); walletCoin.setAvailableAmount(walletCoin.getAvailableAmount().subtract(walletOperateDto.getAmount())); walletCoin.setFrozenAmount(walletCoin.getFrozenAmount().add(walletOperateDto.getAmount())); dappWalletCoinDao.updateById(walletCoin); DappFundFlowEntity fund = new DappFundFlowEntity(member.getId(), walletOperateDto.getAmount(), AppContants.MONEY_TYPE_WITHDRAWAL, 1, new BigDecimal(fee)); dappFundFlowDao.insert(fund); DappAccountMoneyChangeEntity usdtChange = new DappAccountMoneyChangeEntity(member.getId(), preAmount, walletOperateDto.getAmount(), walletCoin.getAvailableAmount(), "USDT申请提现", AppContants.MONEY_TYPE_WITHDRAWAL); dappAccountMoneyChangeDao.insert(usdtChange); } @Override public List recordInPage(RecordInPageDto recordInPageDto) { DappMemberEntity member = LoginUserUtil.getAppUser(); Page page = new Page<>(recordInPageDto.getPageNum(), recordInPageDto.getPageSize()); DappFundFlowEntity dappFundFlowEntity = new DappFundFlowEntity(); if (recordInPageDto.getType() != null && recordInPageDto.getType() != 0) { dappFundFlowEntity.setStatus(recordInPageDto.getType()); } dappFundFlowEntity.setMemberId(member.getId()); IPage records = dappFundFlowDao.selectInPages(page, dappFundFlowEntity); return records.getRecords(); } @Override public List zyInPage(RecordInPageDto recordInPageDto) { DappMemberEntity member = LoginUserUtil.getAppUser(); Page page = new Page<>(recordInPageDto.getPageNum(), recordInPageDto.getPageSize()); DappAchieve dappAchieve = new DappAchieve(); if (recordInPageDto.getType() != null && recordInPageDto.getType() != 0) { dappAchieve.setState(recordInPageDto.getType()); } dappAchieve.setMemberId(member.getId()); IPage records = dappFundFlowDao.selectZyInPage(page, dappAchieve); return records.getRecords(); } @Override public IPage fundFlowInPage(DappFundFlowEntity dappFundFlowEntity, QueryRequest request) { Page page = new Page<>(request.getPageNum(), request.getPageSize()); return dappFundFlowDao.selectInPage(page, dappFundFlowEntity); } @Override @Transactional(rollbackFor = Exception.class) public void withdrawAgreeOrNot(Long id, int type) { DappFundFlowEntity fundFlow = dappFundFlowDao.selectById(id); if (fundFlow == null) { throw new FebsException("数据不存在"); } if (type == 1) { fundFlow.setStatus(DappFundFlowEntity.WITHDRAW_STATUS_AGREE); dappFundFlowDao.updateById(fundFlow); } else if (type == 2) { fundFlow.setStatus(DappFundFlowEntity.WITHDRAW_STATUS_DISAGREE); dappFundFlowDao.updateById(fundFlow); DappMemberEntity dappMemberEntity = dappMemberDao.selectById(fundFlow.getMemberId()); //流水记录的金额是一个负数 dappMemberEntity.setUsdtBalance(dappMemberEntity.getUsdtBalance().subtract(fundFlow.getAmount())); dappMemberDao.updateUsdtBalanceWithVersion(dappMemberEntity); } else { throw new FebsException("参数错误"); } } @Override public IPage walletCoinInPage(DappWalletCoinEntity walletCoin, QueryRequest request) { Page page = new Page<>(request.getPageNum(), request.getPageSize()); return dappWalletCoinDao.selectInPage(walletCoin, page); } @Override public IPage walletMineInPage(DappWalletMineEntity walletMine, QueryRequest request) { Page page = new Page<>(request.getPageNum(), request.getPageSize()); return dappWalletMineDao.selectInPage(walletMine, page); } @Override public IPage accountMoneyChangeInPage(DappAccountMoneyChangeEntity change, QueryRequest request) { Page page = new Page<>(request.getPageNum(), request.getPageSize()); return dappAccountMoneyChangeDao.selectInPage(change, page); } @Override @Transactional(rollbackFor = Exception.class) public Long transfer(TransferDto transferDto) { DappMemberEntity member = LoginUserUtil.getAppUser(); // QueryWrapper objectQueryWrapper = new QueryWrapper<>(); // objectQueryWrapper.eq("type" ,FlowTypeEnum.ZHI_YA.getValue()); // objectQueryWrapper.eq("status" ,DappFundFlowEntity.WITHDRAW_STATUS_AGREE); // objectQueryWrapper.eq("member_id" ,member.getId()); // List dappFundFlowEntities = dappFundFlowDao.selectList(objectQueryWrapper); List dappFundFlowEntities = dappFundFlowDao.selectAmountTotalByTypeAndMemberIdAndDateAndState( member.getId(), FlowTypeEnum.ZHI_YA.getValue(), DappFundFlowEntity.WITHDRAW_STATUS_AGREE, new Date()); BigDecimal zhiyaAmount = new BigDecimal(redisUtils.getString(DataDicEnum.MEMBER_ZHIYA_AMOUNT.getValue())); Integer zhiyaTime = Integer.parseInt(redisUtils.getString(DataDicEnum.MEMBER_ZHIYA_TIME.getValue())); if(CollUtil.isNotEmpty(dappFundFlowEntities)){ if(dappFundFlowEntities.size() >= zhiyaTime){ throw new FebsException("今日暂停质押"); } BigDecimal teamAchieveMemberSum = dappFundFlowEntities.stream().map(DappFundFlowEntity::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add).negate(); if(zhiyaAmount.compareTo(teamAchieveMemberSum.add(transferDto.getAmount())) < 0){ throw new FebsException("今日最多质押"+zhiyaAmount.subtract(teamAchieveMemberSum).setScale(4,BigDecimal.ROUND_DOWN)); } } String hasStart = redisUtils.getString(DataDicEnum.SYSTEM_START_FLAG.getValue()); BigDecimal minAmount = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_BUY_MIN_AMOUNT.getValue())); BigDecimal maxAmount = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_BUY_MAX_AMOUNT.getValue())).setScale(2,BigDecimal.ROUND_DOWN); BigDecimal gfaDays = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_DAYS.getValue())).setScale(2,BigDecimal.ROUND_DOWN); minAmount = minAmount.divide(transferDto.getPrice(),2,BigDecimal.ROUND_DOWN); maxAmount = maxAmount.divide(transferDto.getPrice(),2,BigDecimal.ROUND_DOWN);; if (transferDto.getId() == null) { if (DappFundFlowEntity.TYPE_BUY == transferDto.getType()) { //系统开始标识 if ("start".equals(hasStart)) { if (transferDto.getAmount().compareTo(maxAmount) > 0) { throw new FebsException("超过购买限制"); } if (transferDto.getAmount().compareTo(minAmount) < 0) { throw new FebsException("超过购买限制"); } // if (BigDecimal.ZERO.compareTo(gfaDays) >= 0) { // throw new FebsException("今日暂停质押"); // } if (transferDto.getAmount().compareTo(zhiyaAmount) > 0) { throw new FebsException("今日最多质押"+zhiyaAmount); } } else { throw new FebsException("暂停质押"); } } DappFundFlowEntity fundFlow = new DappFundFlowEntity( member.getId(), transferDto.getAmount().setScale(2,BigDecimal.ROUND_DOWN).negate(), FlowTypeEnum.ZHI_YA.getValue(), DappFundFlowEntity.WITHDRAW_STATUS_ING, BigDecimal.ZERO, transferDto.getTxHash()); fundFlow.setNewestPrice(transferDto.getPrice()); dappFundFlowDao.insert(fundFlow); //发送一个延时队列消息。10分钟流水还没有更新,则删除流水 chainProducer.sendZhiYaDelayFlowMsg(fundFlow.getId(), 10 * 60 * 1000L); return fundFlow.getId(); } if ("success".equals(transferDto.getFlag())) { if (transferDto.getId() == null) { throw new FebsException("网络异常"); } //更新第一次请求的资金划转记录 DappFundFlowEntity flow = dappFundFlowDao.selectById(transferDto.getId()); if(ObjectUtil.isEmpty(flow)){ throw new FebsException("网络异常"); } flow.setFromHash(transferDto.getTxHash()); flow.setStatus(DappFundFlowEntity.WITHDRAW_STATUS_AGREE); flow.setContent(FlowTypeEnum.ZHI_YA.getDescrition()); dappFundFlowDao.updateById(flow); //用户质押代币数量 BigDecimal amount = flow.getAmount().negate(); Long memberId = flow.getMemberId(); //新增一条用户质押记录 DappAchieve dappAchieve = new DappAchieve(); dappAchieve.setMemberId(memberId); dappAchieve.setAmount(amount); BigDecimal achieveReleasePercent = new BigDecimal("0.01").multiply( new BigDecimal(redisUtils.getString(DataDicEnum.GFA_ACHIEVE_RELEASE.getValue())).setScale(2,BigDecimal.ROUND_DOWN) ); dappAchieve.setAmountDay(achieveReleasePercent.multiply(amount).setScale(2,BigDecimal.ROUND_DOWN)); BigDecimal achieveOut = new BigDecimal(redisUtils.getString(DataDicEnum.GFA_ACHIEVE_OUT.getValue())).setScale(2,BigDecimal.ROUND_DOWN); dappAchieve.setAmountMax(achieveOut.multiply(amount).setScale(2,BigDecimal.ROUND_DOWN)); dappAchieve.setState(DappAchieve.STATUS_ING); dappAchieve.setAmountDone(BigDecimal.ZERO); dappAchieveMapper.insert(dappAchieve); asyncCjService.insertTeamPerk(flow.getId(), dappAchieve.getId()); //发送一个延时队列消息。24小时之后产生第一次的质押产出 // chainProducer.sendZhiYaDelayMsg(dappAchieve.getId(), 24 * 60 * 60 * 1000L); } else { dappFundFlowDao.deleteById(transferDto.getId()); } return null; } @Override public String calPrice() { DappMemberEntity member = LoginUserUtil.getAppUser(); return redisUtils.getString(DataDicEnum.GFA_PRICE.getValue()); } @Override public IPage dappAchieveInPage(DappAchieve dappAchieve, QueryRequest request) { Page page = new Page<>(request.getPageNum(), request.getPageSize()); return dappAchieveMapper.selectInPage(page, dappAchieve); } @Override public IPage dappAchieveItemInPage(DappAchieve dappAchieve, QueryRequest request) { Page page = new Page<>(request.getPageNum(), request.getPageSize()); return dappAchieveMapper.dappAchieveItemInPage(page, dappAchieve); } @Override public FebsResponse transferOut(TransferOutDto transferOutDto) { Long memberId = LoginUserUtil.getAppUser().getId(); DappMemberEntity dappMemberEntity = dappMemberDao.selectById(memberId); BigDecimal usdtBalance = dappMemberEntity.getUsdtBalance(); BigDecimal balance = dappMemberEntity.getBalance(); Integer type = transferOutDto.getType(); Integer flowType; String flowDes; BigDecimal amount = transferOutDto.getAmount(); if(1 == type){//代币提现 if(new BigDecimal("10").compareTo(amount) > 0){ throw new FebsException("最小数量为10"); } if(balance.compareTo(amount) < 0){ throw new FebsException("余额不足"); } flowType = FlowTypeEnum.DAI_BI_OUT.getValue(); flowDes = FlowTypeEnum.DAI_BI_OUT.getDescrition(); dappMemberEntity.setBalance(balance.subtract(amount).setScale(2,BigDecimal.ROUND_DOWN)); dappMemberDao.updateBalanceWithVersion(dappMemberEntity); }else{ if(new BigDecimal("100").compareTo(amount) > 0){ throw new FebsException("最小数量为100"); } if(usdtBalance.compareTo(amount) < 0){ throw new FebsException("余额不足"); } flowType = FlowTypeEnum.USDT_OUT.getValue(); flowDes = FlowTypeEnum.USDT_OUT.getDescrition(); dappMemberEntity.setUsdtBalance(usdtBalance.subtract(amount).setScale(2,BigDecimal.ROUND_DOWN)); dappMemberDao.updateUsdtBalanceWithVersion(dappMemberEntity); } DappFundFlowEntity fundFlowTuiJian = new DappFundFlowEntity( memberId, amount.negate(), flowType, DappFundFlowEntity.WITHDRAW_STATUS_ING, flowDes, null, dappMemberEntity.getAddress()); dappFundFlowDao.insert(fundFlowTuiJian); // dappMemberEntity.setBalance(balance.subtract(amount).setScale(2,BigDecimal.ROUND_DOWN)); // dappMemberEntity.setUsdtBalance(usdtBalance.subtract(amount).setScale(2,BigDecimal.ROUND_DOWN)); // dappMemberDao.updateBalanceAndUsdtBalanceWithVersion(dappMemberEntity); return new FebsResponse().success(); } }