KKSU
2025-02-12 1bb96bab1185f2e1aa2f468266512ee0beb83286
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package cc.mrbird.febs.mall.chain.trcCoin.quartz;
 
import cc.mrbird.febs.common.enumerates.RunVipDataDictionaryEnum;
import cc.mrbird.febs.common.enumerates.YesOrNoEnum;
import cc.mrbird.febs.mall.chain.trcCoin.OkHttpUtil2;
import cc.mrbird.febs.mall.chain.trcCoin.OklinkDataPageDetailModel;
import cc.mrbird.febs.mall.chain.trcCoin.OklinkModel;
import cc.mrbird.febs.mall.entity.MallCharge;
import cc.mrbird.febs.mall.mapper.DataDictionaryCustomMapper;
import cc.mrbird.febs.mall.mapper.MallChargeMapper;
import cc.mrbird.febs.rabbit.producter.AgentProducer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
@Slf4j
@Component
@ConditionalOnProperty(prefix = "chain", name = "trc", havingValue = "true")
public class ChainTrcListenerJob {
 
    @Resource
    private DataDictionaryCustomMapper dataDictionaryCustomMapper;
 
    @Resource
    private MallChargeMapper mallChargeMapper;
    @Resource
    private AgentProducer agentProducer;
 
    /**
     * 五分钟  毫秒
     */
    private final static long TIME_INTERVAL_1HOUR = 300000*12;
 
    private final static String TRC20_TRANSFER_API = "https://www.oklink.com/api/v5/explorer/address/token-transaction-list";
    public final static String TRC20_CONTRACT_ADDRESS = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
    public final static String TRC20_NAME = "TRON";
    public final static String TOKEN_20 = "token_20";
 
    /**
     * todo 替换成自己的API-KEY
     */
    private final static String TRON_API_KEY = "21fc662e-03f1-4f60-9124-7b63c0d6c813";
 
    private static Map<String, String> REQUEST_HEADER = new HashMap<>();
    static {
        REQUEST_HEADER.put("Ok-Access-Key", TRON_API_KEY);
    }
 
    @Scheduled(cron = "0 0/2 * * * ? ")
    public void chainBlockUpdate() {
        log.info("TRC20同步");
        String sysAddress = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                RunVipDataDictionaryEnum.CHARGE_SYS_ADDRESS_TRC.getType(),  RunVipDataDictionaryEnum.CHARGE_SYS_ADDRESS_TRC.getCode()
        ).getValue();
        String type = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                RunVipDataDictionaryEnum.CHARGE_TYPE_TRC.getType(),  RunVipDataDictionaryEnum.CHARGE_TYPE_TRC.getCode()
        ).getValue();
 
        if(StrUtil.isBlank(sysAddress)){
            log.info("系统未设置充值地址");
            return;
        }
        // 定时任务的执行时间和转账时间区间间隔5分钟
        // 查询过去5分钟的记录
        Map<String, String> param = new HashMap<>();
        param.put("chainShortName", TRC20_NAME);
        param.put("protocolType", TOKEN_20);
        param.put("tokenContractAddress", TRC20_CONTRACT_ADDRESS);
        param.put("address", sysAddress);
        param.put("limit", "100");
        long l = System.currentTimeMillis();
        byte[] bytes = OkHttpUtil2.doGetSingle(TRC20_TRANSFER_API, REQUEST_HEADER, param, "application/json");
 
        if (bytes == null) {
            log.error("fyTrc20RechargeOklinkTask查询链上数据返回为空,传参:{}",param);
            return;
        }
 
        String s = new String(bytes, StandardCharsets.UTF_8);
        OklinkModel trc20TransfersModel = JSONObject.parseObject(s, OklinkModel.class);
        List<OklinkDataPageDetailModel> tokenTransfers = trc20TransfersModel.getData().get(0).getTransactionList();
        if (CollUtil.isEmpty(tokenTransfers)) {
            return;
        }
        long l1 = System.currentTimeMillis();
        log.info("查询trc耗时:{}", (l1 - l));
 
        // 有记录
        for (OklinkDataPageDetailModel tokenTransfer : tokenTransfers) {
            String transactionTime = tokenTransfer.getTransactionTime();
 
            Long transTime = Long.valueOf(transactionTime);
            if ((transTime + TIME_INTERVAL_1HOUR) < l1) {
                continue;
            }
            // 把1个小时前的数据过滤
            log.info("链上时间:{}", transactionTime);
 
            // 判断收款地址是否是设置的平台地址
            if (sysAddress.equals(tokenTransfer.getTo())) {
 
                String transactionId = tokenTransfer.getTxId();
                LambdaQueryWrapper<MallCharge> mallChargeLambdaQueryWrapper = new LambdaQueryWrapper<>();
                mallChargeLambdaQueryWrapper.eq(MallCharge::getTransHash, transactionId);
                List<MallCharge> list = mallChargeMapper.selectList(mallChargeLambdaQueryWrapper);
                if(CollUtil.isNotEmpty(list)){
                    log.info("扫描到HASH已使用:{}",transactionId);
                    return;
                }
                String fromAddress = tokenTransfer.getFrom();
                if (fromAddress.equals(sysAddress)) {
                    log.info("系统地址转出:{}", transactionId);
                    continue;
                }
 
                BigDecimal amount = new BigDecimal(tokenTransfer.getAmount());
                LambdaQueryWrapper<MallCharge> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MallCharge::getAddress, fromAddress);
                queryWrapper.eq(MallCharge::getSysAddress, sysAddress);
                queryWrapper.eq(MallCharge::getAmount, amount);
                queryWrapper.eq(MallCharge::getType, type);
                queryWrapper.eq(MallCharge::getState, YesOrNoEnum.ING.getValue());
                List<MallCharge> mallCharges = mallChargeMapper.selectList(queryWrapper);
                if(CollUtil.isEmpty(mallCharges)){
                    log.info("未查询到匹配充值记录,充值地址:{},HASH:{}",fromAddress,transactionId);
                    continue;
                }
 
                MallCharge mallCharge = mallCharges.get(0);
                mallCharge.setState(YesOrNoEnum.YES.getValue());
                mallChargeMapper.updateById(mallCharge);
 
                if(StrUtil.isNotEmpty(mallCharge.getVipCode())){
                    agentProducer.sendBuyVipSuccessMsg(mallCharge.getId());
                }else{
                    agentProducer.sendChargeSuccessMsg(mallCharge.getId());
                }
 
                log.info("扫描到用户ID:{},地址:{},充值金额:{}", mallCharge.getMemberId(), fromAddress, amount);
            }
        }
    }
 
}