src/main/java/cc/mrbird/febs/common/contants/AppContants.java
@@ -9,7 +9,7 @@ * 系统用户 */ public static final String SYSTEM_USER = "system"; public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzIfAF0gZs9zn9ENRtz6ocHa8MGljmMmCsjLsRvTIAilBMypMJz/VNooAOhd8GTdsWm8FNGVhRauv7RfxorFJ4Um2UbweUQBIZP2pzZMnclHxhUmYZsn/6IaPzijiUNfEjygtE7ezvso/67ecZJwqfrtlbEjqUbRgo17Qj23suwQIDAQAB"; public static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALMh8AXSBmz3Of0Q1G3PqhwdrwwaWOYyYKyMuxG9MgCKUEzKkwnP9U2igA6F3wZN2xabwU0ZWFFq6/tF/GisUnhSbZRvB5RAEhk/anNkydyUfGFSZhmyf/oho/OKOJQ18SPKC0Tt7O+yj/rt5xknCp+u2VsSOpRtGCjXtCPbey7BAgMBAAECgYAAgn+23IalJ7z0AejA2T7wLotxet+24/zPcOUVY1bxlnMtDMSHWh6mFmjL4cilMXKGqXHO4NwV+zppsCTMPXVMniI1IhfcyECgFjUrpWNCk30DlqhKePtIUCHdyLrc21mMLLMOQD/Hbga5kHZpR8r5poUAJ5Tnm5rjeyggwDj3MwJBAOnY+dyd39cRPtNLH0ANuR0Hd/WuA/RSRNbBTlXIVlc0hF1QXkgIWT2zA4uvwrFsz3F11YdPdfLgUhkFHlQuhVMCQQDEGhJELXqZ3AMlE9ykhUgv9HaCofGuCvzJnBGDKh4B3ufWG728gCNruoaRmzU8TOeVCABIQ2Un3SAenq0ylYUbAkB1y9PJm0lneAtyulPKm18VTW7TNk5No6eDmqqQMbO0iALpUpO7q2Dw4J03n1jusUYp/FaMq61ZpEAW1Go7s5d7AkEArgsJjTLj7ewDaoPfPrD/6XfJOpVqPvKHepOmQ0g9C6H/FtrWIZeEWFdamZ4ruFH08yL/xSLzg1bQ6/wecZecYwJALY4OP1Z81fhNjzg1AQd1CQQJJXUIkQpxXD/zAS5Cgf7XWfELIA4+86WA8qU1ILYHClFuV0SfxyGvI4ZEmpFosg=="; @@ -157,6 +157,8 @@ // 用户购买奖励比例(给上级) public static final String DIC_VALUE_USER_BUY_REWARD = "USER_BUY_REWARD"; public static final String DIC_VALUE_MAKER_MIN_LIMIT = "MAKER_MIN_LIMIT"; // 获取盲盒推荐数量 public static final String DIC_VALUE_BOX_RECOMMEND_CNT = "BOX_RECOMMEND_CNT"; public static final String DESTROY_ADDRESS = "0x0000000000000000000000000000000000000001"; @@ -173,4 +175,6 @@ public static final String IDO_MEMBER_RECOMMEND_CNT = "IDO_MEMBER_RECOMMEND_CNT"; public static final String IDO_BOX_PRIZE = "IDO_BOX_PRIZE"; public static final String REDIS_KEY_SYMBOL_DAILY_PRICE = "SYMBOL_DAILY_PRICE"; } src/main/java/cc/mrbird/febs/dapp/chain/ChainEnum.java
@@ -8,21 +8,6 @@ */ @Getter public enum ChainEnum { /** * 以太坊 USDT合约 */ ETH_USDT("ETH", "0x6c5640c572504a75121e57760909a9dd0E672f2D", "77f650768ff50a4243c008fbae1be9ffe74c52908ee9081e2e15f3d3411690bb", "https://mainnet.infura.io/v3/f54a5887a3894ebb9425920701a97fe0", "0xdac17f958d2ee523a2206206994597c13d831ec7", ""), TRX_USDT("TRX", "TUFzqZRpLwLWJU4jcdf77RKS3Ts2uEhmWL", "e08dce7a4626f97b790e791bcdec31cffab46233744bb1aa133f69f98623d3fb", "", "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "9d461be6-9796-47b9-85d8-b150cbabbb54"), /** * 币安 usdt合约 src/main/java/cc/mrbird/febs/dapp/chain/ChainEnumBak.java
@@ -5,6 +5,7 @@ /** * 链类型 */ @Deprecated @Getter public enum ChainEnumBak { /** src/main/java/cc/mrbird/febs/dapp/entity/DappMemberBoxRecordEntity.java
New file @@ -0,0 +1,30 @@ package cc.mrbird.febs.dapp.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.util.Date; /** * @author wzy * @date 2022-07-28 **/ @Data @TableName("dapp_member_box_record") public class DappMemberBoxRecordEntity { private Date createTime = new Date(); @TableId(value = "id",type = IdType.AUTO) private Long id; private Long memberId; private String address; private Long fromMemberId; private String fromAddress; } src/main/java/cc/mrbird/febs/dapp/entity/DappSymbolDailyPriceEntity.java
New file @@ -0,0 +1,27 @@ package cc.mrbird.febs.dapp.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.math.BigDecimal; import java.util.Date; /** * @author wzy * @date 2022-07-28 **/ @Data @TableName("dapp_symbol_daily_price") public class DappSymbolDailyPriceEntity { private Date createTime = new Date(); private String createBy = "system"; @TableId(value = "id",type = IdType.AUTO) private Long id; private BigDecimal price; } src/main/java/cc/mrbird/febs/dapp/entity/DappWalletCoinEntity.java
@@ -27,11 +27,6 @@ private String address; /** * usdt余额 */ private BigDecimal usdtAmount; /** * 盲盒数量 */ private Integer boxCnt; src/main/java/cc/mrbird/febs/dapp/mapper/DappMemberBoxRecordMapper.java
New file @@ -0,0 +1,12 @@ package cc.mrbird.febs.dapp.mapper; import cc.mrbird.febs.dapp.entity.DappMemberBoxRecordEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; public interface DappMemberBoxRecordMapper extends BaseMapper<DappMemberBoxRecordEntity> { DappMemberBoxRecordEntity selectByFromAddress(@Param("address") String address); DappMemberBoxRecordEntity selectByFromMemberId(@Param("memberId") Long memberId); } src/main/java/cc/mrbird/febs/dapp/mapper/DappSymbolDailyPriceMapper.java
New file @@ -0,0 +1,7 @@ package cc.mrbird.febs.dapp.mapper; import cc.mrbird.febs.dapp.entity.DappSymbolDailyPriceEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface DappSymbolDailyPriceMapper extends BaseMapper<DappSymbolDailyPriceEntity> { } src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java
@@ -3,6 +3,7 @@ import cc.mrbird.febs.dapp.dto.SystemDto; import cc.mrbird.febs.dapp.entity.DappMineDataEntity; import java.math.BigDecimal; import java.util.Map; public interface DappSystemService { @@ -39,4 +40,10 @@ void transferPoolSetting(); void sourcePoolUsdtOutLimitSetting(); void boxCnt(Long id); boolean systemHasStart(); BigDecimal newestPrice(); } src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java
@@ -165,6 +165,9 @@ // 发送购买奖励消息 chainProducer.sendUserBuyReward(fundFlow.getId()); // 发送盲盒消息 chainProducer.sendNftBoxMsg(fundFlow.getId()); } } } src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java
@@ -50,6 +50,9 @@ private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final DappOnlineTransferDao dappOnlineTransferDao; private final ChainProducer chainProducer; private final DappSymbolDailyPriceMapper dappSymbolDailyPriceMapper; private final DappMemberBoxRecordMapper dappMemberBoxRecordMapper; private final DappWalletCoinDao dappWalletCoinDao; @Override @@ -275,6 +278,14 @@ // 中转池交易量 BigDecimal transferPoll = (BigDecimal) transferPoolObj; // 判断今日价格比前一日价格是否跌了,若是,则今天挖矿减半 BigDecimal downReduce = BigDecimal.ONE; if (symbolPriceUpOrDown()) { downReduce = new BigDecimal("0.5"); } BigDecimal totalMineCnt = transferPoll.multiply(new BigDecimal("0.2")).multiply(downReduce); List<DappMemberEntity> allMembers = dappMemberDao.selectList(null); if (CollUtil.isEmpty(allMembers)) { return; @@ -294,7 +305,7 @@ } // 挖矿数量 BigDecimal mine = transferPoll.multiply(new BigDecimal("0.2")).multiply(balance.divide(allInternet, instance.decimals(), RoundingMode.HALF_UP)); BigDecimal mine = totalMineCnt.multiply(balance.divide(allInternet, instance.decimals(), RoundingMode.HALF_UP)); if (mine.compareTo(BigDecimal.ZERO) < 1) { continue; } @@ -354,20 +365,20 @@ } // 判断系统是否启动,如满足条件则启动系统 String hasStart = redisUtils.getString(AppContants.SYSTEM_START_FLAG); if (!"start".equals(hasStart)) { DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.DIC_TYPE_SYSTEM_SETTING, AppContants.DIC_VALUE_SYSTEM_START_TARGET); BigDecimal target = new BigDecimal(dic.getValue()); // 若源池中的USDT达到或超过8万U,则启动整个系统 BigDecimal balance = ChainService.getInstance(ChainEnum.BSC_USDT_SOURCE.name()).balanceOf(ChainEnum.BSC_USDT_SOURCE.getAddress()); if (target.compareTo(balance) < 1) { redisUtils.set(AppContants.SYSTEM_START_FLAG, "start"); // 启动系统 startSystem(); } } // String hasStart = redisUtils.getString(AppContants.SYSTEM_START_FLAG); // if (!"start".equals(hasStart)) { // DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.DIC_TYPE_SYSTEM_SETTING, AppContants.DIC_VALUE_SYSTEM_START_TARGET); // BigDecimal target = new BigDecimal(dic.getValue()); // // // 若源池中的USDT达到或超过8万U,则启动整个系统 // BigDecimal balance = ChainService.getInstance(ChainEnum.BSC_USDT_SOURCE.name()).balanceOf(ChainEnum.BSC_USDT_SOURCE.getAddress()); // if (target.compareTo(balance) < 1) { // redisUtils.set(AppContants.SYSTEM_START_FLAG, "start"); // // // 启动系统 // startSystem(); // } // } } @Override @@ -509,4 +520,111 @@ redisUtils.set(AppContants.REDIS_KEY_USDT_OUT_LIMIT, total); redisUtils.set(AppContants.REDIS_KEY_USDT_OUT_LIMIT_REMAIN, total); } private boolean symbolPriceUpOrDown() { String dailyPrice = redisUtils.getString(AppContants.REDIS_KEY_SYMBOL_DAILY_PRICE); BigDecimal lastDayPrice = BigDecimal.ZERO; if (StrUtil.isNotBlank(dailyPrice)) { lastDayPrice = new BigDecimal(dailyPrice); } ContractChainService tfcInstance = ChainService.getInstance(ChainEnum.BSC_TFC.name()); // 源池币种数量 BigDecimal tfcBalance = tfcInstance.balanceOf(ChainEnum.BSC_TFC.getAddress()); // 源池USDT数量 BigDecimal usdtBalance = ChainService.getInstance(ChainEnum.BSC_USDT.name()).balanceOf(ChainEnum.BSC_USDT.getAddress()); BigDecimal todayPrice = tfcBalance.divide(usdtBalance, tfcInstance.decimals(), RoundingMode.HALF_UP); DappSymbolDailyPriceEntity dailyPriceEntity = new DappSymbolDailyPriceEntity(); dailyPriceEntity.setPrice(todayPrice); this.dappSymbolDailyPriceMapper.insert(dailyPriceEntity); redisUtils.set(AppContants.REDIS_KEY_SYMBOL_DAILY_PRICE, todayPrice.toString()); // 如果价格有跌幅,则挖矿减半 return todayPrice.compareTo(lastDayPrice) < 0; } @Override public void boxCnt(Long id) { DappFundFlowEntity fundFlow = dappFundFlowDao.selectById(id); DappMemberEntity member = dappMemberDao.selectById(fundFlow.getMemberId()); DappMemberEntity parent = dappMemberDao.selectMemberInfoByInviteId(member.getRefererId()); if (parent == null) { return; } DappMemberBoxRecordEntity memberBox = dappMemberBoxRecordMapper.selectByFromMemberId(fundFlow.getMemberId()); if (memberBox != null) { return; } BigDecimal balance = ChainService.getInstance(ChainEnum.BSC_TFC.name()).balanceOf(member.getAddress()); BigDecimal usdtBalance = balance.multiply(newestPrice()); DataDictionaryCustom data = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.DIC_TYPE_SYSTEM_SETTING, AppContants.DIC_VALUE_MINI_HOLD_COIN_LIMIT); BigDecimal miniLimit = new BigDecimal(data.getValue()); if (usdtBalance.compareTo(miniLimit) < 0) { return; } DataDictionaryCustom boxRecommendCnt = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(AppContants.DIC_TYPE_SYSTEM_SETTING, AppContants.DIC_VALUE_BOX_RECOMMEND_CNT); int box = 0; // 需要第一次购买,才在推荐中加1 Object parentRecommend = redisUtils.hget(AppContants.IDO_MEMBER_RECOMMEND_CNT, parent.getAddress()); if (parentRecommend == null) { redisUtils.hset(AppContants.IDO_MEMBER_RECOMMEND_CNT, parent.getAddress(), 1); } else { int i = (int) parentRecommend; // 如果超过10个,则新增一个盲盒,并重置推荐人数 if (++i == new Integer(boxRecommendCnt.getValue())) { box = 1; redisUtils.hset(AppContants.IDO_MEMBER_RECOMMEND_CNT, parent.getAddress(), 0); } else { redisUtils.hset(AppContants.IDO_MEMBER_RECOMMEND_CNT, parent.getAddress(), i); } } if (box > 0) { DappWalletCoinEntity walletCoin = dappWalletCoinDao.selectByMemberId(parent.getId()); walletCoin.setBoxCnt(walletCoin.getBoxCnt() + box); dappWalletCoinDao.updateById(walletCoin); DappMemberBoxRecordEntity memberBoxRecordEntity = new DappMemberBoxRecordEntity(); memberBoxRecordEntity.setMemberId(parent.getId()); memberBoxRecordEntity.setAddress(parent.getAddress()); memberBoxRecordEntity.setFromMemberId(member.getId()); memberBoxRecordEntity.setFromAddress(member.getAddress()); this.dappMemberBoxRecordMapper.insert(memberBoxRecordEntity); DappFundFlowEntity boxFundFlow = new DappFundFlowEntity(parent.getId(), new BigDecimal(box), 5, 2, BigDecimal.ZERO); dappFundFlowDao.insert(boxFundFlow); } } @Override public boolean systemHasStart() { String hasStart = redisUtils.getString(AppContants.SYSTEM_START_FLAG); if (!"start".equals(hasStart)) { log.info("系统未启动"); return false; } return true; } @Override public BigDecimal newestPrice() { if (systemHasStart()) { String dailyPrice = redisUtils.getString(AppContants.REDIS_KEY_SYMBOL_DAILY_PRICE); return StrUtil.isNotBlank(dailyPrice) ? new BigDecimal(dailyPrice) : BigDecimal.ZERO; } else { return new BigDecimal("0.05"); } } } src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java
@@ -60,12 +60,15 @@ List<DappMemberEntity> notDirect = dappMemberDao.selectChildMemberDirectOrNot(member.getInviteId(), 2); BigDecimal childHoldAmount = dappMemberDao.selectChildHoldAmount(member.getInviteId()); DappWalletCoinEntity walletCoin = dappWalletCoinDao.selectByMemberId(member.getId()); walletInfo.setTotalChild(notDirect.size()); walletInfo.setDirectCnt(direct.size()); walletInfo.setTotalChildCoin(childHoldAmount); walletInfo.setTeamReward(map.get("teamReward")); walletInfo.setMiningAmount(map.get("mine")); walletInfo.setInviteId(member.getInviteId()); walletInfo.setBoxCnt(walletCoin.getBoxCnt()); return walletInfo; } src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java
@@ -40,4 +40,7 @@ @ApiModelProperty(value = "团队奖励数量") private BigDecimal teamReward; @ApiModelProperty(value = "盲盒数量") private Integer boxCnt; } src/main/java/cc/mrbird/febs/job/SystemTradeJob.java
@@ -56,15 +56,14 @@ systemService.sourcePoolUsdtOutLimitSetting(); } /** * 挖矿 * * 以中转池成交数1:0.2出矿(中转池卖出多少,矿池则1:0.2出币),每个地址所得=出币量*(单个地址持币量/全网持币量) * source限矿算法: * TODO 按前一天价格,有跌幅则按实际产矿量减半。 * 按前一天价格,有跌幅则按实际产矿量减半。 */ @Scheduled(cron = "0 0 2 * * ?") @Scheduled(cron = "0 0 1 * * ?") public void mineJob() { log.info("挖矿"); systemService.mining(); src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java
@@ -9,4 +9,5 @@ public static final String ONLINE_TRANSFER = "queue_online_transfer"; public static final String DISTRIB_PROFIT = "queue_distrib_profit"; public static final String USER_BUY_REWARD = "queue_user_buy_reward"; public static final String NFT_BOX = "queue_nft_box"; } src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java
@@ -8,7 +8,8 @@ ONLINE_TRANSFER("exchange_online_transfer", "route_key_online_transfer", "queue_online_transfer"), DISTRIB_PROFIT("exchange_distrib_profit", "route_key_distrib_profit", "queue_distrib_profit"), USER_BUY_REWARD("exchange_user_buy_reward", "route_key_user_buy_reward", "queue_user_buy_reward"); USER_BUY_REWARD("exchange_user_buy_reward", "route_key_user_buy_reward", "queue_user_buy_reward"), NFT_BOX("exchange_nft_box", "route_key_nft_box", "queue_nft_box"); private String exchange; src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java
@@ -75,4 +75,22 @@ return BindingBuilder.bind(userBuyRewardQueue()).to(userBuyRewardExchange()).with(QueueEnum.USER_BUY_REWARD.getRoute()); } // === 用户购买奖励 end === // === nft卡牌盲盒 start === @Bean public DirectExchange nftBoxExchange() { return new DirectExchange(QueueEnum.NFT_BOX.getExchange()); } @Bean public Queue nftBoxQueue() { return new Queue(QueueEnum.NFT_BOX.getQueue()); } @Bean public Binding nftBoxBind() { return BindingBuilder.bind(nftBoxQueue()).to(nftBoxExchange()).with(QueueEnum.NFT_BOX.getRoute()); } // === nft卡牌盲盒 end === } src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java
@@ -39,4 +39,10 @@ log.info("收到用户购买奖励消息:{}", id); dappSystemService.userBuyReward(Long.parseLong(id)); } @RabbitListener(queues = QueueConstants.NFT_BOX) public void nftBox(String id) { log.info("收到nft盲盒消息:{}", id); dappSystemService.boxCnt(Long.parseLong(id)); } } src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java
@@ -50,4 +50,10 @@ CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString()); rabbitTemplate.convertAndSend(QueueEnum.USER_BUY_REWARD.getExchange(), QueueEnum.USER_BUY_REWARD.getRoute(), id, correlationData); } public void sendNftBoxMsg(Long id) { log.info("发送NFT盲盒消息:{}", id); CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString()); rabbitTemplate.convertAndSend(QueueEnum.NFT_BOX.getExchange(), QueueEnum.NFT_BOX.getRoute(), id, correlationData); } } src/main/resources/mapper/dapp/DappMemberBoxRecordMapper.xml
New file @@ -0,0 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.mrbird.febs.dapp.mapper.DappMemberBoxRecordMapper"> <select id="selectByFromAddress" resultType="cc.mrbird.febs.dapp.entity.DappMemberBoxRecordEntity"> select * from dapp_member_box_record where from_address=#{address} </select> <select id="selectByFromMemberId" resultType="cc.mrbird.febs.dapp.entity.DappMemberBoxRecordEntity"> select * from dapp_member_box_record where from_member_id=#{memberId} </select> </mapper> src/main/resources/mapper/dapp/DappSymbolDailyPriceMapper.xml
New file @@ -0,0 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="cc.mrbird.febs.dapp.mapper.DappSymbolDailyPriceMapper"> </mapper>