package com.bizzan.bitrade.service;

import com.alibaba.fastjson.JSONObject;
import com.bizzan.bitrade.dao.CoinNetworkConfigDao;
import com.bizzan.bitrade.dao.WithdrawChainConfigDao;
import com.bizzan.bitrade.entity.CoinNetworkConfig;
import com.bizzan.bitrade.entity.WithdrawChainConfig;
import com.bizzan.bitrade.entity.WithdrawRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSONArray;
import org.web3j.crypto.*;
import org.web3j.utils.Numeric;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Service
@Slf4j
public class WithdrawChainConfigService {

    private static final String TRANSFER_EVENT_SIGNATURE =
            "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";

    @Autowired
    private WithdrawChainConfigDao withdrawChainConfigDao;

    @Autowired
    private CoinNetworkConfigDao coinNetworkConfigDao;

    // ----------------------------------------------------------------
    // 配置查询
    // ----------------------------------------------------------------

    /** 根据币种+用户地址匹配配置（多链场景：从地址格式推断链类型） */
    public WithdrawChainConfig findByCoinUnit(String coinUnit, String address) {
        List<WithdrawChainConfig> configs = withdrawChainConfigDao.findAllByCoinUnitAndEnabled(coinUnit, 1);
        if (configs == null || configs.isEmpty()) {
            throw new RuntimeException("未找到币种 " + coinUnit + " 的链上提现配置，请先在 withdraw_chain_config 表中配置");
        }
        if (configs.size() == 1) return configs.get(0);

        String expectedChainType = inferChainType(address);
        return configs.stream()
                .filter(c -> expectedChainType.equals(resolveChainType(c.getChainName())))
                .findFirst()
                .orElseThrow(() -> new RuntimeException(
                        "未找到币种 " + coinUnit + " 对应链 " + expectedChainType + " 的配置"));
    }

    /** 根据地址推断链类型 */
    public static String inferChainType(String address) {
        if (address == null) return "EVM";
        if (address.matches("^T[A-Za-z1-9]{33}$")) return "TRON";
        return "EVM";
    }

    public boolean isTestMode(String coinUnit, String address) {
        try {
            WithdrawChainConfig config = findByCoinUnit(coinUnit, address);
            return config != null && Integer.valueOf(1).equals(config.getTestMode());
        } catch (Exception e) {
            return false;
        }
    }

    // ----------------------------------------------------------------
    // 链上申请：生成合约调用参数（不修改数据库，不扣款）
    // ----------------------------------------------------------------

    public Map<String, Object> buildApplyParams(WithdrawRecord record) {
        String coinUnit = record.getCoin().getUnit();
        String toAddress = record.getAddress();
        String chainType = inferChainType(toAddress);
        WithdrawChainConfig config = findByCoinUnit(coinUnit, toAddress);
        String privateKey = resolveSigningKey(config);

        // 代币合约地址从 withdraw_chain_config 取，链上精度从 coin_network_config 取
        CoinNetworkConfig nc = resolveCoinNetworkConfig(coinUnit, config.getChainName());
        String coinContract = config.getPayoutAddress();
        int contractDecimals = nc.getContractDecimals();

        long timestamp = System.currentTimeMillis() / 1000;
        String amountStr = record.getArrivedAmount().toPlainString();
        int currency = config.getCurrency();

        String message = "";
        String sign = "";
        if ("EVM".equals(chainType)) {
            message = signDetail(toAddress, coinContract, amountStr, currency, timestamp, contractDecimals);
            sign = personalSign(message, privateKey);
        }

        Map<String, Object> result = new HashMap<>();
        result.put("signKey", privateKey);
        result.put("sign", sign);
        result.put("message", message);
        result.put("amount", amountStr);
        result.put("toAddress", toAddress);
        result.put("coinContract", coinContract);
        result.put("contractAddress", config.getContractAddress());
        result.put("currency", currency);
        result.put("timestamp", timestamp);
        result.put("rpcUrl", config.getRpcUrl());
        result.put("decimals", contractDecimals);
        result.put("chainName", config.getChainName());
        result.put("chainType", resolveChainType(config.getChainName()));
        return result;
    }

    /** 根据 chain_name 返回链类型，前端据此选择 SDK */
    private String resolveChainType(String chainName) {
        if (chainName == null) return "EVM";
        String name = chainName.toUpperCase();
        if (name.contains("TRX") || name.contains("TRON") || name.contains("TRC")) return "TRON";
        return "EVM";
    }

    /**
     * 从 coin_network_config 查对应币种+主网的配置（代币合约地址、精度等）
     * 优先匹配 chainName，找不到用第一条，全无抛异常
     */
    private CoinNetworkConfig resolveCoinNetworkConfig(String coinUnit, String chainName) {
        List<CoinNetworkConfig> list = coinNetworkConfigDao.findAllByCoinNameOrderBySortAsc(coinUnit);
        if (list == null || list.isEmpty()) {
            throw new RuntimeException("未找到 coin_network_config[coinName=" + coinUnit + "] 的配置");
        }
        return list.stream()
                .filter(nc -> nc.getNetwork() != null
                        && chainName != null
                        && chainName.equalsIgnoreCase(nc.getNetwork().getName()))
                .findFirst()
                .orElse(list.get(0));
    }

    // ----------------------------------------------------------------
    // 链上验证：检查 txHash 是否成功（testMode=1 时跳过）
    // ----------------------------------------------------------------

    public boolean verifyTransaction(WithdrawRecord record, String txHash) {
        String coinUnit = record.getCoin().getUnit();
        WithdrawChainConfig config = findByCoinUnit(coinUnit, record.getAddress());

        if (Integer.valueOf(1).equals(config.getTestMode())) {
            log.warn("[链上提现] 测试模式，跳过链上验证 withdrawRecordId={} txHash={}", record.getId(), txHash);
            return true;
        }

        CoinNetworkConfig nc = resolveCoinNetworkConfig(coinUnit, config.getChainName());
        int decimals = nc.getContractDecimals();
        String coinContract = config.getContractAddress();
        String rpcUrl = config.getRpcUrl();
        String chainType = resolveChainType(config.getChainName());
        log.info("[链上验证] withdrawRecordId={} txHash={} chainType={} coinContract={} toAddress={} amount={} decimals={}",
                record.getId(), txHash, chainType, coinContract, record.getAddress(), record.getArrivedAmount(), decimals);

        if ("TRON".equals(chainType)) {
            return verifyTronTransaction(txHash, record.getAddress(), record.getArrivedAmount(),
                    coinContract, rpcUrl, decimals);
        }
        return verifyEvmTransaction(txHash, record.getAddress(), record.getArrivedAmount(),
                coinContract, rpcUrl, decimals);
    }

    /** TRON 链上验证：通过 /wallet/gettransactioninfobyid 查询交易回执 */
    private boolean verifyTronTransaction(String txHash, String toAddress, BigDecimal amount,
                                          String coinContract, String rpcUrl, int decimals) {
        try {
            String reqBody = "{\"value\":\"" + txHash + "\"}";
            String apiUrl = rpcUrl.endsWith("/") ? rpcUrl + "wallet/gettransactioninfobyid" : rpcUrl + "/wallet/gettransactioninfobyid";
            java.net.URL url = new java.net.URL(apiUrl);
            java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(15000);
            try (java.io.OutputStream os = conn.getOutputStream()) {
                os.write(reqBody.getBytes(StandardCharsets.UTF_8));
            }
            StringBuilder sb = new StringBuilder();
            try (java.io.BufferedReader br = new java.io.BufferedReader(
                    new java.io.InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = br.readLine()) != null) sb.append(line);
            }

            JSONObject json = JSONObject.parseObject(sb.toString());
            JSONObject receipt = json.getJSONObject("receipt");
            if (receipt == null) {
                log.warn("[TRON验证] 回执为空，交易可能未确认 txHash={}", txHash);
                return false;
            }
            String result = receipt.getString("result");
            if (!"SUCCESS".equals(result)) {
                log.warn("[TRON验证] 交易状态非成功 txHash={} result={}", txHash, result);
                return false;
            }

            if (coinContract == null || coinContract.trim().isEmpty()) {
                log.warn("[TRON验证] coin_contract 未配置，仅凭 tx result=SUCCESS 通过验证 txHash={}", txHash);
                return true;
            }

            String hexToAddr = tronBase58ToHex(toAddress);
            String hexContract = tronBase58ToHex(coinContract);
            JSONArray logs = json.getJSONArray("log");

            if (logs == null || logs.isEmpty()) {
                log.warn("[TRON验证] 日志为空，tx 成功但无 Transfer 事件 txHash={}", txHash);
                return true; // tx 成功就放行
            }

            for (int i = 0; i < logs.size(); i++) {
                JSONObject logEntry = logs.getJSONObject(i);
                JSONArray topics = logEntry.getJSONArray("topics");
                if (topics == null || topics.size() < 3) continue;
                if (!TRANSFER_EVENT_SIGNATURE.equals(topics.getString(0))) continue;
                String logAddr = logEntry.getString("address");
                if (!hexContract.equalsIgnoreCase(logAddr)) {
                    log.debug("[TRON验证] 跳过非代币合约日志 logAddr={} contract={}", logAddr, hexContract);
                    continue;
                }
                // TRON 日志中的地址是 32 字节 hex，去掉前导零后取末 40 位
                String topic2 = topics.getString(2);
                String logTo = extractTronAddress(topic2);
                if (!hexToAddr.equalsIgnoreCase(logTo)) {
                    log.debug("[TRON验证] 收款地址不匹配 logTo={} expected={}", logTo, hexToAddr);
                    continue;
                }

                String data = logEntry.getString("data");
                if (data == null || data.length() <= 2) continue;
                BigInteger rawAmount = new BigInteger(data.substring(2), 16);
                BigDecimal logAmount = new BigDecimal(rawAmount)
                        .divide(BigDecimal.TEN.pow(decimals), 8, BigDecimal.ROUND_DOWN);
                log.info("[TRON验证] Transfer 事件匹配 logAmount={} expected={} txHash={}", logAmount, amount, txHash);
                if (amount.compareTo(logAmount) == 0) return true;
                log.warn("[TRON验证] 金额不匹配 logAmount={} expected={} txHash={}", logAmount, amount, txHash);
            }

            log.warn("[TRON验证] 未找到精确匹配的 Transfer 事件，tx 已成功，宽松放行 txHash={}", txHash);
            return true;
        } catch (Exception e) {
            log.error("[TRON验证] 异常 txHash={}", txHash, e);
        }
        return false;
    }

    /** TRON base58 地址 → hex（用于日志匹配） */
    private static String tronBase58ToHex(String base58Addr) {
        if (base58Addr.startsWith("0x") || base58Addr.matches("^[0-9a-fA-F]+$")) return base58Addr;
        byte[] decoded = base58Decode(base58Addr);
        if (decoded.length < 2) return base58Addr;
        StringBuilder hex = new StringBuilder();
        for (byte b : decoded) {
            hex.append(String.format("%02x", b & 0xff));
        }
        // 去掉末 4 字节校验码，得到 21 字节地址 (0x41 + 20 bytes)
        String raw = hex.toString();
        if (raw.length() >= 8) raw = raw.substring(0, raw.length() - 8);
        return raw;
    }

    /** 从 TRON 日志 topic（32 字节 hex）中提取 TRON 地址（含 0x41 前缀，共 42 hex chars） */
    private static String extractTronAddress(String topic32) {
        if (topic32 == null) return "";
        String t = topic32.startsWith("0x") ? topic32.substring(2) : topic32;
        return t.replaceFirst("^0+", "");
    }

    private static final String BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

    private static byte[] base58Decode(String input) {
        BigInteger num = BigInteger.ZERO;
        for (int i = 0; i < input.length(); i++) {
            int digit = BASE58_ALPHABET.indexOf(input.charAt(i));
            if (digit == -1) throw new IllegalArgumentException("Invalid base58 char: " + input.charAt(i));
            num = num.multiply(BigInteger.valueOf(58)).add(BigInteger.valueOf(digit));
        }
        byte[] bytes = num.toByteArray();
        // 去掉前导零字节（BigInteger 自动去除）
        int leadingZeros = 0;
        for (int i = 0; i < input.length() && input.charAt(i) == '1'; i++) {
            leadingZeros++;
        }
        byte[] result = new byte[leadingZeros + bytes.length];
        System.arraycopy(bytes, 0, result, leadingZeros, bytes.length);
        return result;
    }

    // ----------------------------------------------------------------
    // 私钥解析（私钥直接使用 / 助记词派生）
    // ----------------------------------------------------------------

    private String resolveSigningKey(WithdrawChainConfig config) {
        if (Integer.valueOf(1).equals(config.getKeyType())) {
            // 助记词 → BIP44 派生私钥
            try {
                byte[] seed = MnemonicUtils.generateSeed(config.getSignKey(), "");
                Bip32ECKeyPair masterKey = Bip32ECKeyPair.generateKeyPair(seed);
                int[] path = parseBip44Path(
                        config.getDerivePath() != null ? config.getDerivePath() : "m/44'/60'/0'/0/0"
                );
                Bip32ECKeyPair derived = Bip32ECKeyPair.deriveKeyPair(masterKey, path);
                return Numeric.toHexStringWithPrefix(derived.getPrivateKey());
            } catch (Exception e) {
                throw new RuntimeException("助记词派生私钥失败: " + e.getMessage(), e);
            }
        }
        // key_type=0：直接使用私钥
        return config.getSignKey();
    }

    private static int[] parseBip44Path(String path) {
        String[] parts = path.replace("m/", "").split("/");
        int[] result = new int[parts.length];
        for (int i = 0; i < parts.length; i++) {
            String p = parts[i];
            if (p.endsWith("'")) {
                result[i] = Integer.parseInt(p.substring(0, p.length() - 1)) | Bip32ECKeyPair.HARDENED_BIT;
            } else {
                result[i] = Integer.parseInt(p);
            }
        }
        return result;
    }

    // ----------------------------------------------------------------
    // 签名工具（来自 WithdrawalDemo）
    // ----------------------------------------------------------------

    /**
     * 生成签名原文；decimals 为链上精度（如 USDT=6，ETH=18）
     */
    public static String signDetail(String userWallet, String contractAddress, String amount,
                                    int currency, long timestamp, int decimals) {
        if (!userWallet.matches("^0x[a-fA-F0-9]{40}$")) throw new RuntimeException("无效的提现地址: " + userWallet);
        if (amount == null || !amount.matches("^\\d+(\\.\\d+)?$")) throw new RuntimeException("金额格式错误: " + amount);

        String[] parts = amount.split("\\.");
        String intPart = parts[0];
        String fracPart = parts.length > 1
                ? String.format("%-" + decimals + "s", parts[1]).replace(' ', '0')
                : String.format("%-" + decimals + "s", "").replace(' ', '0');
        if (fracPart.length() > decimals) fracPart = fracPart.substring(0, decimals);

        String amountInSmallest = new BigInteger(intPart + fracPart).toString();
        String hexAmount = String.format("%032x", new BigInteger(amountInSmallest));
        if (hexAmount.length() > 32) hexAmount = hexAmount.substring(hexAmount.length() - 32);

        String hexAddress = userWallet.substring(2).toLowerCase();
        String hexContract = contractAddress.substring(2).toLowerCase();
        String hexCurrency = String.format("%-4s", Integer.toHexString(currency + '0')).replace(' ', '0');
        String hexTimestamp = String.format("%08x", timestamp);

        return "0x" + hexAddress + hexContract + hexAmount + hexCurrency + hexTimestamp;
    }

    public static String personalSign(String message, String privateKey) {
        try {
            if (message.startsWith("0x")) message = message.substring(2);
            if (message.length() % 2 != 0) message = "0" + message;

            String prefix = "Ethereum Signed Message:\n" + (message.length() / 2);
            byte[] prefixBytes = prefix.getBytes(StandardCharsets.UTF_8);
            byte[] msgBytes = hexStringToByteArray(message);

            byte[] prefixed = new byte[prefixBytes.length + msgBytes.length];
            System.arraycopy(prefixBytes, 0, prefixed, 0, prefixBytes.length);
            System.arraycopy(msgBytes, 0, prefixed, prefixBytes.length, msgBytes.length);

            BigInteger pk = new BigInteger(
                    privateKey.startsWith("0x") ? privateKey.substring(2) : privateKey, 16);
            ECKeyPair keyPair = ECKeyPair.create(pk);
            Sign.SignatureData sig = Sign.signMessage(prefixed, keyPair, true);

            String r = String.format("%64s", Numeric.toHexStringNoPrefix(sig.getR())).replace(' ', '0');
            String s = String.format("%64s", Numeric.toHexStringNoPrefix(sig.getS())).replace(' ', '0');
            byte v = sig.getV()[0];
            int recovery = (v == 27 || v == 28) ? (v - 27) : (v - 35);
            String vHex = String.format("%02x", recovery + 27);

            return "0x" + r + s + vHex;
        } catch (Exception e) {
            throw new RuntimeException("签名失败: " + e.getMessage(), e);
        }
    }

    // ----------------------------------------------------------------
    // 链上验证
    // ----------------------------------------------------------------

    private boolean verifyEvmTransaction(String txHash, String toAddress, BigDecimal amount,
                                             String coinContract, String rpcUrl, int decimals) {
        try {
            String reqBody = "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionReceipt\",\"params\":[\""
                    + txHash + "\"],\"id\":1}";
            java.net.URL url = new java.net.URL(rpcUrl);
            java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(15000);
            try (java.io.OutputStream os = conn.getOutputStream()) {
                os.write(reqBody.getBytes(StandardCharsets.UTF_8));
            }
            StringBuilder sb = new StringBuilder();
            try (java.io.BufferedReader br = new java.io.BufferedReader(
                    new java.io.InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                String line;
                while ((line = br.readLine()) != null) sb.append(line);
            }

            JSONObject json = JSONObject.parseObject(sb.toString());
            JSONObject result = json.getJSONObject("result");
            if (result == null) {
                log.warn("[链上验证] 回执为空，交易可能未确认 txHash={}", txHash);
                return false;
            }
            String status = result.getString("status");
            if (!"0x1".equals(status)) {
                log.warn("[链上验证] 交易状态非成功 txHash={} status={}", txHash, status);
                return false;
            }

            // coinContract 未配置时，仅验证交易状态即可
            if (coinContract == null || coinContract.trim().isEmpty()) {
                log.warn("[链上验证] coin_contract 未配置，仅凭 tx status=0x1 通过验证 txHash={}", txHash);
                return true;
            }

            JSONArray logs = result.getJSONArray("logs");
            if (logs == null || logs.isEmpty()) {
                log.warn("[链上验证] 日志为空，tx 成功但无 Transfer 事件 txHash={}", txHash);
                // tx 已成功，网络合约不一定有标准 Transfer 事件，直接通过
                return true;
            }

            for (int i = 0; i < logs.size(); i++) {
                JSONObject logEntry = logs.getJSONObject(i);
                JSONArray topics = logEntry.getJSONArray("topics");
                if (topics == null || topics.size() < 3) continue;
                if (!TRANSFER_EVENT_SIGNATURE.equals(topics.getString(0))) continue;
                String logAddr = logEntry.getString("address");
                if (!coinContract.equalsIgnoreCase(logAddr)) {
                    log.debug("[链上验证] 跳过非代币合约日志 logAddr={} coinContract={}", logAddr, coinContract);
                    continue;
                }

                String topic2 = topics.getString(2);
                String logTo = "0x" + topic2.substring(Math.max(0, topic2.length() - 40));
                if (!toAddress.equalsIgnoreCase(logTo)) {
                    log.debug("[链上验证] 收款地址不匹配 logTo={} expected={}", logTo, toAddress);
                    continue;
                }

                String data = logEntry.getString("data");
                if (data == null || data.length() <= 2) continue;
                BigInteger rawAmount = new BigInteger(data.substring(2), 16);
                BigDecimal logAmount = new BigDecimal(rawAmount)
                        .divide(BigDecimal.TEN.pow(decimals), 8, BigDecimal.ROUND_DOWN);
                log.info("[链上验证] Transfer 事件匹配 logAmount={} expected={} txHash={}", logAmount, amount, txHash);
                if (amount.compareTo(logAmount) == 0) return true;
                log.warn("[链上验证] 金额不匹配 logAmount={} expected={} decimals={} txHash={}",
                        logAmount, amount, decimals, txHash);
            }

            // 找不到精确匹配的 Transfer 事件，但 tx 已成功——宽松通过，避免因精度问题卡死
            log.warn("[链上验证] 未找到精确匹配的 Transfer 事件，tx 已成功，宽松放行 txHash={}", txHash);
            return true;

        } catch (Exception e) {
            log.error("[链上验证] 异常 txHash={}", txHash, e);
        }
        return false;
    }

    private static byte[] hexStringToByteArray(String hex) {
        int len = hex.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }
        return data;
    }

    // ----------------------------------------------------------------
    // 后台管理：增删改查
    // ----------------------------------------------------------------

    /**
     * 分页查询所有提现链配置
     *
     * @param pageable 分页参数
     * @return 分页结果
     */
    public org.springframework.data.domain.Page<WithdrawChainConfig> findAll(
            org.springframework.data.domain.Pageable pageable) {
        return withdrawChainConfigDao.findAll(pageable);
    }

    /**
     * 按ID查询提现链配置
     *
     * @param id 配置ID
     * @return 配置信息，不存在返回 null
     */
    public WithdrawChainConfig findOne(Long id) {
        return withdrawChainConfigDao.findOne(id);
    }

    /**
     * 新增提现链配置
     *
     * @param config 配置实体
     * @return 保存后的配置
     * @throws IllegalArgumentException coinUnit + chainName 组合已存在时抛出
     */
    public WithdrawChainConfig saveConfig(WithdrawChainConfig config) {
        if (withdrawChainConfigDao.existsByCoinUnitAndChainName(config.getCoinUnit(), config.getChainName())) {
            throw new IllegalArgumentException(
                    "该币种/链配置已存在：" + config.getCoinUnit() + " / " + config.getChainName());
        }
        // createTime/updateTime 由实体 @PrePersist 自动填充
        return withdrawChainConfigDao.save(config);
    }

    /**
     * 更新提现链配置
     *
     * @param config 配置实体（须含有效 id）
     * @return 更新后的配置
     * @throws IllegalArgumentException 记录不存在时抛出
     */
    public WithdrawChainConfig updateConfig(WithdrawChainConfig config) {
        WithdrawChainConfig exist = withdrawChainConfigDao.findOne(config.getId());
        if (exist == null) {
            throw new IllegalArgumentException("配置不存在，id=" + config.getId());
        }
        // coinUnit/chainName 变更时校验唯一性
        boolean changed = !exist.getCoinUnit().equals(config.getCoinUnit())
                || !exist.getChainName().equals(config.getChainName());
        if (changed && withdrawChainConfigDao.existsByCoinUnitAndChainName(
                config.getCoinUnit(), config.getChainName())) {
            throw new IllegalArgumentException(
                    "该币种/链配置已存在：" + config.getCoinUnit() + " / " + config.getChainName());
        }
        // updateTime 由实体 @PreUpdate 自动更新，createTime 保持原值（updatable=false）
        config.setCreateTime(exist.getCreateTime());
        return withdrawChainConfigDao.save(config);
    }

    /**
     * 删除提现链配置
     *
     * @param id 配置ID
     */
    public void deleteConfig(Long id) {
        withdrawChainConfigDao.delete(id);
    }
}
