jean 1 lună în urmă
părinte
comite
3a08a0bdee

+ 0 - 8
doge/core/src/main/java/com/bizzan/bitrade/dao/CoinDao.java

@@ -70,14 +70,6 @@ public interface CoinDao extends JpaRepository<Coin, String>, JpaSpecificationEx
     List<Coin> findAllRechargeParentCoins(@Param("canRecharge") BooleanEnum canRecharge,
                                           @Param("status") CommonStatus status);
 
-    /**
-     * 查询可内部转账的顶级币种(parentCoinName 为空、canTransfer=true、状态正常),按 sort 升序
-     */
-    @Query("select c from Coin c where c.canTransfer = :canTransfer and c.status = :status "
-            + "and (c.parentCoinName is null or c.parentCoinName = '') order by c.sort asc")
-    List<Coin> findAllTransferParentCoins(@Param("canTransfer") BooleanEnum canTransfer,
-                                          @Param("status") CommonStatus status);
-
     /**
      * 查询所有顶级币种名称(parentCoinName 为空),用于"上级币种"下拉选择
      *

+ 0 - 8
doge/core/src/main/java/com/bizzan/bitrade/service/CoinService.java

@@ -89,14 +89,6 @@ public class CoinService extends BaseService {
         return coinDao.findAllRechargeParentCoins(IS_TRUE, CommonStatus.NORMAL);
     }
 
-    /**
-     * 查询可内部转账的顶级币种(parentCoinName 为空、canTransfer=true、状态正常),按 sort 升序
-     */
-    @Transactional(readOnly = true)
-    public List<Coin> findAllTransferParentCoins() {
-        return coinDao.findAllTransferParentCoins(IS_TRUE, CommonStatus.NORMAL);
-    }
-
     public Coin findByUnit(String unit) {
         return coinDao.findByUnit(unit);
     }

+ 53 - 9
doge/core/src/main/java/com/bizzan/bitrade/service/StakingService.java

@@ -91,12 +91,12 @@ public class StakingService extends BaseService {
             return MessageResult.error(msService.getMessage("STAKING_AMOUNT_INVALID"));
         }
 
-        BigDecimal price = redisManager.getSpotPriceUsdt(config.getCoinUnit());
+        BigDecimal price = resolveSpotPriceUsdt(config.getCoinUnit());
         if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
             return MessageResult.error(msService.getMessage("STAKING_PRICE_UNAVAILABLE"));
         }
 
-        Coin coin = coinService.findByUnit(config.getCoinUnit());
+        Coin coin = resolveCoinByUnit(config.getCoinUnit());
         if (coin == null) {
             return MessageResult.error(msService.getMessage("COIN_ILLEGAL"));
         }
@@ -114,13 +114,54 @@ public class StakingService extends BaseService {
             return MessageResult.error(msService.getMessage("STAKING_USDT_INSUFFICIENT"));
         }
 
+        String stakeUnit = coin.getUnit();
         MessageResult swapResult = memberWalletService.flashSwapUsdtToCoin(
-                memberId, config.getCoinUnit(), usdtAmount, price);
+                memberId, stakeUnit, usdtAmount, price);
         if (swapResult.getCode() != 0) {
             return swapResult;
         }
 
-        return executeStake(memberId, configId, config, coinAmount);
+        return executeStake(memberId, configId, config, stakeUnit, coinAmount);
+    }
+
+    /**
+     * 从 Redis ExchangeNew2:latestPrice 解析币种 USDT 价(field 如 ibitusdt)
+     */
+    @Transactional(readOnly = true)
+    public BigDecimal resolveSpotPriceUsdt(String coinUnit) {
+        if (coinUnit == null || coinUnit.trim().isEmpty()) {
+            return null;
+        }
+        String unit = coinUnit.trim();
+        BigDecimal price = redisManager.getSpotPriceUsdt(unit);
+        if (price != null && price.compareTo(BigDecimal.ZERO) > 0) {
+            return price;
+        }
+        Coin coin = resolveCoinByUnit(unit);
+        if (coin != null && coin.getUnit() != null) {
+            price = redisManager.getSpotPriceUsdt(coin.getUnit());
+            if (price != null && price.compareTo(BigDecimal.ZERO) > 0) {
+                return price;
+            }
+        }
+        return null;
+    }
+
+    /** 按 unit 查 coin,兼容大小写 */
+    public Coin resolveCoinByUnit(String coinUnit) {
+        if (coinUnit == null || coinUnit.trim().isEmpty()) {
+            return null;
+        }
+        String unit = coinUnit.trim();
+        Coin coin = coinService.findByUnit(unit);
+        if (coin != null) {
+            return coin;
+        }
+        coin = coinService.findByUnit(unit.toUpperCase());
+        if (coin != null) {
+            return coin;
+        }
+        return coinService.findByUnit(unit.toLowerCase());
     }
 
     /**
@@ -149,12 +190,15 @@ public class StakingService extends BaseService {
             return MessageResult.error(msService.getMessage("STAKING_INSUFFICIENT_BALANCE"));
         }
 
-        return executeStake(memberId, configId, config, amount);
+        Coin coin = resolveCoinByUnit(config.getCoinUnit());
+        String stakeUnit = coin != null ? coin.getUnit() : config.getCoinUnit();
+        return executeStake(memberId, configId, config, stakeUnit, amount);
     }
 
     /** 资金账户扣款并创建质押订单(调用前须已完成余额/金额校验) */
-    private MessageResult executeStake(Long memberId, Long configId, StakingConfig config, BigDecimal amount) {
-        MessageResult freezeResult = memberWalletService.stakeFundToLocked(memberId, config.getCoinUnit(), amount);
+    private MessageResult executeStake(Long memberId, Long configId, StakingConfig config, String coinUnit,
+                                       BigDecimal amount) {
+        MessageResult freezeResult = memberWalletService.stakeFundToLocked(memberId, coinUnit, amount);
         if (freezeResult.getCode() != 0) {
             return freezeResult;
         }
@@ -162,10 +206,10 @@ public class StakingService extends BaseService {
         Date stakingTime = new Date();
         Date unlockTime = calcUnlockTime(stakingTime, config.getLockDays());
 
-        StakingOrder order = buildStakingOrder(memberId, configId, config.getCoinUnit(), amount, stakingTime, unlockTime);
+        StakingOrder order = buildStakingOrder(memberId, configId, coinUnit, amount, stakingTime, unlockTime);
         stakingOrderDao.save(order);
 
-        StakingRecord record = buildStakingRecord(memberId, order.getId(), config.getCoinUnit(), amount, 0, "用户质押");
+        StakingRecord record = buildStakingRecord(memberId, order.getId(), coinUnit, amount, 0, "用户质押");
         stakingRecordDao.save(record);
 
         return MessageResult.success("质押成功");

+ 3 - 3
doge/ucenter-api/src/main/java/com/bizzan/bitrade/controller/CoinNetworkController.java

@@ -157,12 +157,12 @@ public class CoinNetworkController extends BaseController {
     }
 
     /**
-     * 内部转账:可转的顶级币种(coin 表 parentCoinName 为空且 canTransfer=true
+     * 内部转账:可选主币(与充值一致:无上级且可充值
      */
-    @ApiOperation(value = "内部转账可选主币", notes = "返回 coin 表中 parent_coin_name 为空且 can_transfer=true 的顶级币种")
+    @ApiOperation(value = "内部转账可选主币", notes = "返回 coin 表中 parent_coin_name 为空且 can_recharge=true 的顶级币种")
     @GetMapping("transfer-parents")
     public MessageResult listTransferParentCoins() {
-        return success(coinService.findAllTransferParentCoins());
+        return success(coinService.findAllRechargeParentCoins());
     }
 
     /**

+ 25 - 24
doge/ucenter-api/src/main/java/com/bizzan/bitrade/controller/StakingController.java

@@ -21,7 +21,9 @@ import org.springframework.web.bind.annotation.*;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static com.bizzan.bitrade.constant.SysConstant.SESSION_MEMBER;
 
@@ -52,6 +54,25 @@ public class StakingController {
     @Autowired
     private RedisTemplate<String, String> redisTemplate;
 
+    /**
+     * 查询现货最新价(Redis ExchangeNew2:latestPrice,与 IDO 闪兑、质押折算同源)
+     */
+    @ApiOperation(value = "查询质押币现货价", notes = "从 Redis 读取 coinUnit 对 USDT 价格,如 IBIT → ibitusdt")
+    @GetMapping("/spot-price")
+    public MessageResult getSpotPrice(@RequestParam("coinUnit") String coinUnit) {
+        if (coinUnit == null || coinUnit.trim().isEmpty()) {
+            return MessageResult.error(msService.getMessage("PARAMETER_ERROR"));
+        }
+        BigDecimal price = stakingService.resolveSpotPriceUsdt(coinUnit.trim());
+        if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) {
+            return MessageResult.error(msService.getMessage("STAKING_PRICE_UNAVAILABLE"));
+        }
+        Map<String, Object> data = new HashMap<>(2);
+        data.put("coinUnit", coinUnit.trim().toUpperCase());
+        data.put("price", price.toPlainString());
+        return MessageResult.success("success", data);
+    }
+
     /**
      * 查询启用中的质押配置列表,供用户选择质押产品
      *
@@ -97,36 +118,16 @@ public class StakingController {
         StakingWallet wallet = memberWalletService.findStakingWallet(member.getId(), coinUnit.trim());
 
         // 2. 从 Redis 读取现货价格(ExchangeNew2:latestPrice,field 格式如 ibitusdt)
-        java.math.BigDecimal price = getSpotPriceUsdt(coinUnit.trim());
+        java.math.BigDecimal price = stakingService.resolveSpotPriceUsdt(coinUnit.trim());
+        if (price == null) {
+            price = java.math.BigDecimal.ZERO;
+        }
 
         // 3. 构建响应 VO
         StakingWalletVo vo = buildStakingWalletVo(member.getId(), wallet, coinUnit.trim(), price);
         return MessageResult.success("success", vo);
     }
 
-    /**
-     * 从 Redis ExchangeNew2:latestPrice 读取指定币种对 USDT 的现货价格
-     *
-     * @param coinUnit 币种,如 IBIT
-     * @return 价格,无行情时返回 ZERO
-     */
-    private java.math.BigDecimal getSpotPriceUsdt(String coinUnit) {
-        if ("USDT".equalsIgnoreCase(coinUnit)) {
-            return java.math.BigDecimal.ONE;
-        }
-        try {
-            // Redis field 格式:ibitusdt(全小写)
-            String field = coinUnit.toLowerCase() + "usdt";
-            Object val = redisTemplate.opsForHash().get("ExchangeNew2:latestPrice", field);
-            if (val != null) {
-                return new java.math.BigDecimal(val.toString());
-            }
-        } catch (Exception e) {
-            log.warn("[staking/wallet] 读取 Redis 价格失败 coinUnit={}, error={}", coinUnit, e.getMessage());
-        }
-        return java.math.BigDecimal.ZERO;
-    }
-
     /**
      * 构建质押钱包余额 VO,包含原始锁定数量及 USDT 折算值
      *