package cc.mrbird.febs.dapp.chain; import cc.mrbird.febs.common.exception.FebsException; import cn.hutool.core.lang.func.Func1; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONObject; import io.reactivex.Flowable; import io.reactivex.Observable; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; import lombok.extern.slf4j.Slf4j; import org.reactivestreams.Publisher; import org.springframework.data.repository.query.ParameterOutOfBoundsException; import org.web3j.crypto.Credentials; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.DefaultBlockParameter; import org.web3j.protocol.core.DefaultBlockParameterName; import org.web3j.protocol.core.DefaultBlockParameterNumber; import org.web3j.protocol.core.methods.request.EthFilter; import org.web3j.protocol.core.methods.response.TransactionReceipt; import org.web3j.protocol.http.HttpService; import org.web3j.tx.gas.StaticGasProvider; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.rmi.activation.UnknownObjectException; import java.time.Duration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @author * @date 2022-03-23 **/ @Slf4j public class ChainService { private final static Map contractMap = new HashMap<>(); static { for (ChainEnum chain : ChainEnum.values()) { if ("TRX".equals(chain.getChain())) { contractMap.put(chain.name(), new TrxService(chain.getAddress(), chain.getPrivateKey(), chain.getContractAddress(), chain.getApiKey())); } else { contractMap.put(chain.name(), new EthService(chain.getUrl(), chain.getAddress(), chain.getPrivateKey(), chain.getContractAddress())); } } } private ChainService() { } public final static ChainService INSTANCE = new ChainService(); public static ContractChainService getInstance(String chainType) { ContractChainService contract = contractMap.get(chainType); if (contract == null) { throw new FebsException("参数错误"); } return contract; } /** * 监听合约事件 * @param startBlock 开始区块 */ public static void contractEventListener(BigInteger startBlock, ContractEventService event, String type) { contractEventListener(startBlock, null, event, type); } public static void contractEventListener(BigInteger startBlock, BigInteger endBlock, ContractEventService event, String type) { ChainEnum chain = ChainEnum.getValueByName(type); assert chain != null; EthUsdtContract contract = contract(chain.getPrivateKey(), chain.getContractAddress(), chain.getUrl()); EthFilter filter = getFilter(startBlock, endBlock, chain.getContractAddress()); Flowable eventFlowable = contract.transferEventFlowable(filter); eventFlowable.subscribe(e -> { event.compile(e); }, error -> { log.error("合约监听启动报错", error); }); } // public static void coinRewardEventListener(BigInteger startBlock, BigInteger endBlock, ContractEventService event, String type) { // ChainEnum chain = ChainEnum.getValueByName(type); // assert chain != null; // // EthUsdtContract contract = contract(chain.getPrivateKey(), chain.getContractAddress(), chain.getUrl()); // EthFilter filter = getFilter(startBlock, endBlock, chain.getContractAddress()); // // Flowable eventFlowable = contract.coinRewardEventFlowable(filter); // eventFlowable.subscribe(e -> { // event.coinReward(e); // }, error -> { // log.error("合约监听启动报错", error); // }); // } public static void coinRewardEventListener(BigInteger startBlock, BigInteger endBlock, ContractEventService event, String type) { ChainEnum chain = ChainEnum.getValueByName(type); assert chain != null; EthUsdtContract contract = contract(chain.getPrivateKey(), chain.getContractAddress(), chain.getUrl()); EthFilter filter = getFilter(startBlock, endBlock, chain.getContractAddress()); Flowable eventFlowable = contract.coinRewardEventFlowable(filter) .doOnError(throwable -> log.error("合约事件监听发生错误: " + throwable.getMessage(), throwable)) // 更具体的错误日志记录 .subscribeOn(Schedulers.io()); // 指定subscribe操作在IO线程中执行,避免阻塞主线程 eventFlowable.subscribe( e -> { try { event.coinReward(e); // 处理事件 } catch (Exception ex) { // 处理事件时可能出现的异常 log.error("处理合约事件时出错", ex); } }, Throwable::printStackTrace, // 打印错误堆栈,或者可以替换为更具体的错误处理逻辑 () -> log.info("合约事件监听已完成") // 在Flowable完成时执行的逻辑,如记录日志等 ); } private static EthUsdtContract contract(String privateKey, String contractAddress, String url) { Credentials credentials = Credentials.create(privateKey); return EthUsdtContract.load(contractAddress, Web3j.build(new HttpService(url)), credentials, new StaticGasProvider(BigInteger.valueOf(4500000L), BigInteger.valueOf(200000L))); } private static EthFilter getFilter(BigInteger startBlock, String contractAddress) { return getFilter(startBlock, null, contractAddress); } private static EthFilter getFilter(BigInteger startBlock, BigInteger endBlock, String contractAddress) { DefaultBlockParameter startParameterName = null; DefaultBlockParameter endParameterName = null; if (startBlock != null) { startParameterName = new DefaultBlockParameterNumber(startBlock); } else { startParameterName = DefaultBlockParameterName.EARLIEST; } if (endBlock != null) { endParameterName = new DefaultBlockParameterNumber(endBlock); } else { endParameterName = DefaultBlockParameterName.LATEST; } return new EthFilter(startParameterName, endParameterName, contractAddress); } /** * --todo 替换 * @param args */ public static void main(String[] args) { /** * 替换两个合约的地址 */ String contractAddress = ChainEnum.BSC_USDT.getContractAddress(); String contractAddress1 = ChainEnum.BSC_GFA.getContractAddress(); /** * 滑点接收钱包 * GiveMeMoneyJob * mineJob * address参数 */ BigDecimal coinCnt = ChainService.getInstance(ChainEnum.BSC_GFA.name()).balanceOf("0xF6b06A30196aA5E318232a3b61319eab0FD4A3bF").setScale(8,BigDecimal.ROUND_DOWN); BigDecimal coinPrice = ChainService.getInstance(ChainEnum.BSC_GFA.name()).getPrice("0xF6b06A30196aA5E318232a3b61319eab0FD4A3bF").setScale(8,BigDecimal.ROUND_DOWN); /** * 批量转账的钱包地址 * 注意钱包地址和私钥一起替换 */ String address = ChainEnum.BSC_USDT.getAddress(); String address1 = ChainEnum.BSC_GFA.getAddress(); } }