From f658569891db433854221b80f0a9fa99608cff64 Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Fri, 03 Apr 2026 18:22:34 +0800
Subject: [PATCH] 1

---
 trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeLeverApplyOrderController.java |   15 
 trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractApplyOrderDTO.java                       |    5 
 trading-order-service/src/main/java/com/yami/trading/UD/UdunUtils.java                                               |   84 ++
 trading-order-service/src/main/resources/mapper/contract/ContractOrderMapper.xml                                     |    1 
 docs/api/模拟账户-前端对接文档.md                                                                                              |   14 
 trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java                            |   15 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java                           |    9 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiGoogleAuthController.java                       |   14 
 trading-order-admin/src/main/resources/logback/logback-dev.xml                                                       |   19 
 trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractApplyOrder.java                       |    4 
 trading-order-service/src/main/resources/mapper/contract/ContractApplyOrderMapper.xml                                |    1 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java      |   17 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractOrderController.java                    |    1 
 trading-order-service/src/main/java/com/yami/trading/UD/Address.java                                                 |   31 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java                         |  225 ++++-
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java                      |  293 ++++++--
 trading-order-service/src/main/java/com/yami/trading/service/impl/FollowWalletServiceImpl.java                       |   20 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiC2cOrderController.java                         |   15 
 trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java            |   28 
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java                 |   79 +
 trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java       |  271 ++++++-
 trading-order-admin/src/main/java/com/yami/trading/api/dto/CloseAction.java                                          |    2 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java                             |   34 +
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiSpotStocksController.java                   |    2 
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java       |  130 ++-
 trading-order-service/src/main/java/com/yami/trading/service/impl/WalletServiceImpl.java                             |   20 
 trading-order-service/src/main/java/com/yami/trading/UD/Coin.java                                                    |   78 ++
 trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java                               |   18 
 trading-order-common/src/main/java/com/yami/trading/common/constants/Constants.java                                  |    2 
 trading-order-admin/src/main/java/com/yami/trading/api/dto/OpenAction.java                                           |   11 
 trading-order-service/src/main/java/com/yami/trading/UD/CryptoCurrencyEnum.java                                      |   91 ++
 trading-order-admin/src/main/resources/application-dev.yml                                                           |    5 
 trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java                            |    8 
 trading-order-service/src/main/java/com/yami/trading/UD/UdunException.java                                           |   28 
 trading-order-service/src/main/java/com/yami/trading/UD/UdunApi.java                                                 |  108 +++
 trading-order-service/src/main/java/com/yami/trading/UD/UdunClient.java                                              |  151 ++++
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java                            |   35 +
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractApplyOrderController.java               |   24 
 trading-order-service/src/main/java/com/yami/trading/UD/ApiPath.java                                                 |   12 
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiApplyNewSharesOrderController.java          |    2 
 trading-order-service/src/main/java/com/yami/trading/UD/ResultMsg.java                                               |   40 +
 trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java                                  |    5 
 trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java      |    2 
 43 files changed, 1,622 insertions(+), 347 deletions(-)

diff --git "a/docs/api/\346\250\241\346\213\237\350\264\246\346\210\267-\345\211\215\347\253\257\345\257\271\346\216\245\346\226\207\346\241\243.md" "b/docs/api/\346\250\241\346\213\237\350\264\246\346\210\267-\345\211\215\347\253\257\345\257\271\346\216\245\346\226\207\346\241\243.md"
index 41b7f69..84e333b 100644
--- "a/docs/api/\346\250\241\346\213\237\350\264\246\346\210\267-\345\211\215\347\253\257\345\257\271\346\216\245\346\226\207\346\241\243.md"
+++ "b/docs/api/\346\250\241\346\213\237\350\264\246\346\210\267-\345\211\215\347\253\257\345\257\271\346\216\245\346\226\207\346\241\243.md"
@@ -112,7 +112,8 @@
 ### 3. 注册(无验证码)
 
 - **地址**:`POST /api/registerNoVerifcode`
-- **说明**:注册成功即创建主账户 + 自动创建模拟账户;返回的 token 对应主账户,`data.info` 结构同 2。
+- **说明**:注册成功即创建主账户 + 自动创建模拟账户;返回的 token 对应主账户,`data.info` 结构同 2。  
+  额外限制:**禁止大陆邮箱注册**,命中时返回业务错误(如:`msg = "大陆邮箱不支持注册"`)。
 - **请求体**:JSON
 
 | 参数     | 类型   | 必填 | 说明 |
@@ -129,7 +130,8 @@
 ### 4. 注册(有验证码)
 
 - **地址**:`POST /api/registerVerifcode`
-- **说明**:同上,注册即主账户+模拟账户;返回结构同 2、3。
+- **说明**:同上,注册即主账户+模拟账户;返回结构同 2、3。  
+  额外限制:**禁止大陆邮箱注册**,命中时返回业务错误(如:`msg = "大陆邮箱不支持注册"`)。
 - **请求体**:在 3 的基础上增加 `verifcode`(验证码)等字段,按现有注册接口约定即可。
 
 ---
@@ -213,7 +215,10 @@
 
 4. **错误处理**  
    - `msg === "模拟账户不能直接登录,请使用主账户登录后切换"`:提示用户使用主账户登录后再切换。  
-   - `msg === "模拟账户不支持充值"` / `"模拟账户不支持提现"`:在模拟账户下隐藏或禁用对应功能即可,一般不应让用户点到。
+   - `msg === "模拟账户不支持充值"` / `"模拟账户不支持提现"`:在模拟账户下隐藏或禁用对应功能即可,一般不应让用户点到。  
+   - `msg === "大陆IP禁止访问"`:提示当前地区不可用,并阻断后续页面访问。  
+   - `msg === "大陆邮箱不支持注册"`:在注册页保持提交按钮可重试,提示用户更换邮箱。  
+   - `msg === "请先完成两步认证并设置资金密码后再交易"`:交易页入口/下单按钮置灰,并引导跳转安全设置页。
 
 ---
 
@@ -235,3 +240,6 @@
 - 所有上述接口的**基础路径**以实际部署为准(如 `https://your-domain.com`),若有统一网关前缀需自行加上。
 - Token 过期或未传时,接口会返回 401 等,前端需按现有逻辑跳转登录(主账户登录页)。
 - 模拟账户与主账户**共用同一套业务接口**(交易、资产等),仅充提与登录限制不同;前端通过 `accountType` 控制展示与禁用即可。
+- 访问控制:**禁止大陆 IP 访问**,命中后端风控时应返回业务错误(建议文案:`大陆IP禁止访问`),前端需阻断继续使用。
+- 注册限制:**禁止大陆邮箱注册**,在注册接口统一拦截并返回业务错误(建议文案:`大陆邮箱不支持注册`)。
+- 交易前置条件:用户必须先完成**两步认证(2FA)**并**设置资金密码**,否则不得进行交易下单(建议文案:`请先完成两步认证并设置资金密码后再交易`)。
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiC2cOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiC2cOrderController.java
index fdb27bd..a3f2c1f 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiC2cOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiC2cOrderController.java
@@ -171,14 +171,6 @@
                 throw new BusinessException("用户未结束订单数量已达上限");
             }
         }
-        // C2C用户下单是否需要基础认证(true:是,false:否)
-        Object obj = this.sysparaService.find("c2c_order_need_kyc");
-        if (null != obj) {
-            if (!party.isRealNameAuthority()
-                    && "true".equals(this.sysparaService.find("c2c_order_need_kyc").getSvalue())) {
-                throw new YamiShopBindException("401", "未实名认证,是否认证?");
-            }
-        }
         // C2C每日订单取消最大次数
         int orderCancelDayTimes = 0;
         Map<String, Integer> map = (Map<String, Integer>) redisTemplate.opsForValue().get(RedisKeys.C2C_ORDER_CANCEL_DAY_TIMES);
@@ -370,13 +362,6 @@
             if (null != obj2) {
                 if (nofinishOrderCount >= Long.valueOf(this.sysparaService.find("c2c_nofinish_order_count_max").getSvalue()).longValue()) {
                     throw new YamiShopBindException("用户未结束订单数量已达上限");
-                }
-            }
-            // C2C用户下单是否需要基础认证(true:是,false:否)
-            Object obj = this.sysparaService.find("c2c_order_need_kyc");
-            if (null != obj) {
-                if (!party.isRealNameAuthority() && "true".equals(this.sysparaService.find("c2c_order_need_kyc").getSvalue())) {
-                    return Result.succeed("未实名认证,是否认证?");
                 }
             }
             // C2C每日订单取消最大次数
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractApplyOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractApplyOrderController.java
index 19b3b69..b8c5650 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractApplyOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractApplyOrderController.java
@@ -215,7 +215,7 @@
         RLock rLock = null;
         boolean lockResult = false;
         try {
-        	String partyId = SecurityUtils.getUser().getUserId();
+        	String partyId = SecurityUtils.getCurrentUserId();
             rLock = redissonClient.getLock("contract_open_" + partyId);
             
             lockResult = rLock.tryLock(5, TimeUnit.SECONDS);
@@ -227,14 +227,12 @@
             if (!user.isEnabled()) {
                 throw new YamiShopBindException("用户已锁定");
             }
+            validateTradePermission(user);
 
             Syspara syspara = sysparaService.find("stop_user_internet");
             String stopUserInternet = syspara.getSvalue();
             if(org.apache.commons.lang3.StringUtils.isNotEmpty(stopUserInternet)) {
                 String[] stopUsers = stopUserInternet.split(",");
-
-                System.out.println("userName = " + user.getUserName());
-                System.out.println("stopUserInternet = " + stopUserInternet);
 
                 if(Arrays.asList(stopUsers).contains(user.getUserName())){
                     throw new YamiShopBindException("无网络");
@@ -294,14 +292,12 @@
             if (!user.isEnabled()) {
                 throw new YamiShopBindException("用户已锁定");
             }
+            validateTradePermission(user);
 
             Syspara syspara = sysparaService.find("stop_user_internet");
             String stopUserInternet = syspara.getSvalue();
             if(org.apache.commons.lang3.StringUtils.isNotEmpty(stopUserInternet)) {
                 String[] stopUsers = stopUserInternet.split(",");
-
-                System.out.println("userName = " + user.getUserName());
-                System.out.println("stopUserInternet = " + stopUserInternet);
 
                 if(Arrays.asList(stopUsers).contains(user.getUserName())){
                     throw new YamiShopBindException("无网络");
@@ -392,6 +388,7 @@
         map.put("amount", order.getVolume().multiply(order.getUnitAmount()).setScale(4, RoundingMode.FLOOR));
         map.put("amount_open", order.getVolumeOpen().multiply(order.getUnitAmount()));
         map.put("fee", order.getFee());
+        map.put("funding_fee", order.getFundingFee());
         map.put("deposit", order.getDeposit());
         return Result.succeed(map);
     }
@@ -578,4 +575,17 @@
         dateN.put("count", count);
         return Result.ok(dateN);
     }
+
+    private void validateTradePermission(User user) {
+        if (user == null) {
+            throw new YamiShopBindException("用户不存在");
+        }
+        // 模拟账户不做二步校验限制
+        if (user.getAccountType() != null && user.getAccountType() == 1) {
+            return;
+        }
+        if (!user.isGoogleAuthBind() || StringUtils.isEmptyString(user.getSafePassword())) {
+            throw new YamiShopBindException("请先完成两步认证并设置资金密码后再交易");
+        }
+    }
 }
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractOrderController.java
index 7900530..898fd8a 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiContractOrderController.java
@@ -26,6 +26,7 @@
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.*;
 
 /**
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiGoogleAuthController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiGoogleAuthController.java
index 6dc6332..8f46459 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiGoogleAuthController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiGoogleAuthController.java
@@ -23,7 +23,7 @@
 
 @RestController
 @CrossOrigin
-@RequestMapping("api/gooleAuth")
+@RequestMapping({"api/gooleAuth", "api/googleAuth"})
 @Api(tags = "谷歌验证码")
 public class ApiGoogleAuthController {
     @Autowired
@@ -47,6 +47,12 @@
         dto.setGoogleAuthImg(base64);
         dto.setGoogleAuthSecret(secretKey);
         return Result.succeed(dto);
+    }
+
+    @GetMapping("/get.action")
+    @ApiOperation(value = "H5-谷歌身份验证器 获取密钥及二维码")
+    public Result<GoogleAuthDto> getAction() {
+        return get();
     }
 
     @PostMapping("/bind")
@@ -74,4 +80,10 @@
             throw new YamiShopBindException("谷歌验证码错误");
         }
     }
+
+    @PostMapping("/bind.action")
+    @ApiOperation(value = "H5-谷歌身份绑定")
+    public Result bindAction(@Valid GoogleAuthBindModel model) {
+        return bind(model);
+    }
 }
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java
index 89d1b59..c433882 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiIndexController.java
@@ -602,6 +602,7 @@
     @PostMapping("/login")
     @ApiOperation(value = "账号密码(用于前端登录)", notes = "通过账号/手机号/用户名密码登录,还要携带用户的类型,也就是用户所在的系统")
     public Result login(@Valid UserLoginModel model, HttpServletResponse httpResponse) {
+        validateMainlandIpAccess();
         String mobileOrUserName = model.getUserName();
         User user = null;
         if (model.getType() == 1) {
@@ -676,6 +677,8 @@
     @PostMapping("/registerNoVerifcode")
     @ApiOperation(value = "手机/邮箱/用户名注册(无验证码)")
     public Result register(@Valid RegisterModel model) {
+        validateMainlandIpAccess();
+        validateMainlandEmailRegister(model.getUserName(), model.getType());
 
         String username = model.getUserName();
         String password = model.getPassword();
@@ -716,6 +719,8 @@
     @PostMapping("/registerVerifcode")
     @ApiOperation(value = "手机(有验证码)")
     public Result registerVerifcode(@Valid RegisterMobile model) {
+        validateMainlandIpAccess();
+        validateMainlandEmailRegister(model.getUserName(), model.getType());
 
         String username = model.getUserName();
         String password = model.getPassword();
@@ -889,4 +894,34 @@
         return resultObject;
     }
 
+    private void validateMainlandIpAccess() {
+        String clientIp = IPHelper.getIpAddr();
+        List<RiskClient> riskList = RiskClientUtil.getRiskInfoByIp(clientIp, "badnetwork");
+        if (CollectionUtil.isNotEmpty(riskList)) {
+            throw new YamiShopBindException("大陆IP禁止访问");
+        }
+    }
+
+    private void validateMainlandEmailRegister(String userName, Integer type) {
+        if (type == null || type != 2 || StringUtils.isEmptyString(userName)) {
+            return;
+        }
+        int atPos = userName.lastIndexOf("@");
+        if (atPos <= 0 || atPos >= userName.length() - 1) {
+            return;
+        }
+        String domain = userName.substring(atPos + 1).trim().toLowerCase();
+        if (domain.endsWith(".cn")) {
+            throw new YamiShopBindException("大陆邮箱不支持注册");
+        }
+        Set<String> blockedDomains = new HashSet<>(Arrays.asList(
+                "qq.com", "foxmail.com", "163.com", "126.com", "yeah.net",
+                "sina.com", "sina.cn", "sohu.com", "aliyun.com", "21cn.com",
+                "189.cn", "tom.com"
+        ));
+        if (blockedDomains.contains(domain)) {
+            throw new YamiShopBindException("大陆邮箱不支持注册");
+        }
+    }
+
 }
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java
index a1c56d9..f33025d 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiUserController.java
@@ -1,6 +1,7 @@
 package com.yami.trading.api.controller;
 
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import com.yami.trading.api.dto.UserDto;
 import com.yami.trading.api.model.SetSafewordModel;
 import com.yami.trading.api.service.UserCacheService;
@@ -11,6 +12,7 @@
 import com.yami.trading.bean.model.UserRecom;
 import com.yami.trading.bean.model.UserSimRelation;
 import com.yami.trading.bean.model.UserSafewordApply;
+import com.yami.trading.bean.model.RiskClient;
 import com.yami.trading.bean.syspara.domain.Syspara;
 import com.yami.trading.common.constants.Constants;
 import com.yami.trading.common.domain.Result;
@@ -32,6 +34,7 @@
 import com.yami.trading.security.common.manager.TokenStore;
 import com.yami.trading.security.common.util.SecurityUtils;
 import com.yami.trading.security.common.vo.TokenInfoVO;
+import com.yami.trading.security.common.util.RiskClientUtil;
 import com.yami.trading.service.HighLevelAuthRecordService;
 import com.yami.trading.service.IdentifyingCodeTimeWindowService;
 import com.yami.trading.service.QRGenerateService;
@@ -110,6 +113,7 @@
      */
     @GetMapping("login")
     public Result login(String username, String password) {
+        validateMainlandIpAccess();
         if (StringUtils.isEmptyString(username)) {
             throw new YamiShopBindException("用户名不能为空");
         }
@@ -287,11 +291,13 @@
      */
     @RequestMapping("register")
     public Object register(String username, String password, String safeword, String verifcode, String usercode, String type) {
+        validateMainlandIpAccess();
         // 注册类型:1/手机;2/邮箱;
         String error = this.validateParam(username, verifcode, password, type);
         if (!StringUtils.isNullOrEmpty(error)) {
             throw new YamiShopBindException(error);
         }
+        validateMainlandEmailRegister(username, type);
 //        if (StringUtils.isEmptyString(safeword)) {
 //            throw new YamiShopBindException("资金密码不能为空");
 //        }
@@ -972,6 +978,7 @@
         String username = null;
         try {
             username = request.getParameter("username").replace(" ", "");
+            validateMainlandIpAccess();
             String password = request.getParameter("password").replace(" ", "");
             String safeword = request.getParameter("safeword").replace(" ", "");
             String usercode = request.getParameter("usercode");
@@ -1101,4 +1108,31 @@
         return null;
     }
 
+    private void validateMainlandIpAccess() {
+        String clientIp = IPHelper.getIpAddr();
+        List<RiskClient> riskList = RiskClientUtil.getRiskInfoByIp(clientIp, "badnetwork");
+        if (CollectionUtil.isNotEmpty(riskList)) {
+            throw new YamiShopBindException("大陆IP禁止访问");
+        }
+    }
+
+    private void validateMainlandEmailRegister(String username, String type) {
+        if (!"2".equals(type) || StringUtils.isEmptyString(username)) {
+            return;
+        }
+        int atPos = username.lastIndexOf("@");
+        if (atPos <= 0 || atPos >= username.length() - 1) {
+            return;
+        }
+        String domain = username.substring(atPos + 1).trim().toLowerCase();
+        if (domain.endsWith(".cn")) {
+            throw new YamiShopBindException("大陆邮箱不支持注册");
+        }
+        if (Arrays.asList("qq.com", "foxmail.com", "163.com", "126.com", "yeah.net",
+                "sina.com", "sina.cn", "sohu.com", "aliyun.com", "21cn.com",
+                "189.cn", "tom.com").contains(domain)) {
+            throw new YamiShopBindException("大陆邮箱不支持注册");
+        }
+    }
+
 }
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
index 3124efe..860252f 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWalletController.java
@@ -263,7 +263,14 @@
                     return type.indexOf(symbolType.toUpperCase()) != -1;
                 }).collect(Collectors.toList());
             } else {
-                list_it = list_it.stream().filter(i -> symbolType.equalsIgnoreCase(i.getType())).collect(Collectors.toList());
+                // 与 /api/publicRealtimeByType 保持一致:按 sorted 倒序,再按 type 过滤(不分页)
+                list_it = itemService.cacheGetAll().stream()
+                        .sorted(Comparator.comparing(
+                                item -> Integer.parseInt(item.getSorted()),
+                                Comparator.reverseOrder()
+                        ))
+                        .filter(i -> symbolType.equalsIgnoreCase(i.getType()))
+                        .collect(Collectors.toList());
             }
         }
         List<String> list_symbol = new ArrayList<>();
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
index 1401100..7ac8952 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiWithdrawController.java
@@ -1,7 +1,17 @@
 package com.yami.trading.api.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpStatus;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yami.trading.UD.Coin;
+import com.yami.trading.UD.ResultMsg;
+import com.yami.trading.UD.UdunClient;
+import com.yami.trading.UD.UdunException;
 import com.yami.trading.api.util.ServletUtil;
+import com.yami.trading.bean.item.domain.Item;
 import com.yami.trading.bean.model.User;
 import com.yami.trading.bean.model.Withdraw;
 import com.yami.trading.common.constants.Constants;
@@ -59,6 +69,8 @@
     PasswordEncoder passwordEncoder;
     @Autowired
     private IdentifyingCodeTimeWindowService identifyingCodeTimeWindowService;
+    @Autowired
+    UdunClient udunClient;
 
     @Override
     public void afterPropertiesSet() throws Exception {
@@ -97,53 +109,136 @@
     public Result apply(HttpServletRequest request, String session_token, String safeword,
                         String amount, String from, String currency,
                         String channel, String language, String verifcode_type, String verifcode_value) {
-        String partyId = SecurityUtils.getUser().getUserId();
-        User currentUser = userService.getById(partyId);
-        if (currentUser != null && currentUser.getAccountType() != null && currentUser.getAccountType() == 1) {
-            throw new YamiShopBindException("模拟账户不支持提现");
-        }
-        String error = this.verif(amount);
-        if (!StringUtils.isNullOrEmpty(error)) {
-            throw new YamiShopBindException(error);
-        }
-        double amount_double = Double.valueOf(amount).doubleValue();
-        // 交易所提现是否需要资金密码
-        String exchange_withdraw_need_safeword = this.sysparaService.find("exchange_withdraw_need_safeword").getSvalue();
-        if (StringUtils.isEmptyString(exchange_withdraw_need_safeword)) {
-            throw new YamiShopBindException("系统参数错误");
-        }
-        // 开关打开,则验证
-        if ("true".equals(exchange_withdraw_need_safeword)) {
-            // 资金密码验证
-            if (StringUtils.isEmptyString(safeword)) {
-                throw new YamiShopBindException("资金密码不能为空");
+        Result resultObject=new Result();
+        try {
+            String partyId = SecurityUtils.getUser().getUserId();
+            String error = this.verif(amount);
+            if (!StringUtils.isNullOrEmpty(error)) {
+                throw new YamiShopBindException(error);
             }
-            if (safeword.length() < 6 || safeword.length() > 12) {
-                throw new YamiShopBindException("资金密码必须6-12位");
+            double amount_double = Double.valueOf(amount).doubleValue();
+            // 交易所提现是否需要资金密码
+            String exchange_withdraw_need_safeword = this.sysparaService.find("exchange_withdraw_need_safeword").getSvalue();
+            if (StringUtils.isEmptyString(exchange_withdraw_need_safeword)) {
+                throw new YamiShopBindException("系统参数错误");
             }
-            if (!userService.checkLoginSafeword(SecurityUtils.getUser().getUserId(), safeword)) {
-                throw new YamiShopBindException("资金密码错误");
+            // 开关打开,则验证
+            if ("true".equals(exchange_withdraw_need_safeword)) {
+                // 资金密码验证
+                if (StringUtils.isEmptyString(safeword)) {
+                    throw new YamiShopBindException("资金密码不能为空");
+                }
+                if (safeword.length() < 6 || safeword.length() > 12) {
+                    throw new YamiShopBindException("资金密码必须6-12位");
+                }
+                if (!userService.checkLoginSafeword(SecurityUtils.getUser().getUserId(), safeword)) {
+                    throw new YamiShopBindException("资金密码错误");
+                }
+                if (StringUtils.isNotEmpty(verifcode_type)) {
+                    // 校验用户的验证码
+                    userService.checkCode(partyId, verifcode_type, verifcode_value);
+                }
             }
-            if (StringUtils.isNotEmpty(verifcode_type)) {
-                // 校验用户的验证码
-                userService.checkCode(partyId, verifcode_type, verifcode_value);
-            }
-        }
-        Object object = this.sessionTokenService.cacheGet(session_token);
-        this.sessionTokenService.del(session_token);
+            Object object = this.sessionTokenService.cacheGet(session_token);
+            this.sessionTokenService.del(session_token);
 //        if (null == object || !SecurityUtils.getUser().getUserId().equals((String) object)) {
 //            throw new YamiShopBindException("请稍后再试");
 //        }
-        Withdraw withdraw = new Withdraw();
-        withdraw.setUserId(partyId);
-        withdraw.setVolume(new BigDecimal(amount_double));
-        withdraw.setAddress(from);
-        withdraw.setCurrency(currency);
-        withdraw.setTx("");
-        withdraw.setDeviceIp(ServletUtil.getIp(request));
-        // 保存
-        this.withdrawService.saveApply(withdraw, channel, null, language);
-        return Result.succeed(null);
+            Withdraw withdraw = new Withdraw();
+            withdraw.setUserId(partyId);
+            withdraw.setVolume(new BigDecimal(amount_double));
+            withdraw.setAddress(from);
+            withdraw.setCurrency(currency);
+            withdraw.setTx("");
+            withdraw.setDeviceIp(ServletUtil.getIp(request));
+
+
+            //获取商户支持币种
+            List<Coin> coinList = udunClient.listSupportCoin(false);
+            String channelName ;
+            if (channel.toUpperCase().contains("USDC")) {
+                channelName = "USDC";
+            } else {
+                channelName = channel.replace("_", "");
+            }
+            Coin coin = coinList.stream().filter(x -> x.getName().replace("-","").equals(channelName)).findFirst().orElse(null);
+            if (coin == null) {
+                throw new YamiShopBindException("不支持的提现币种");
+            }
+            if (!udunClient.checkAddress(coin.getMainCoinType(), from)) {
+                throw new YamiShopBindException("提现地址异常");
+            }
+
+            // 保存
+            this.withdrawService.saveApply(withdraw, channel, null, language);
+            ResultMsg resultMsg = udunClient.withdraw(from, withdraw.getVolume(), coin.getMainCoinType(),
+                    coin.getCoinType(), withdraw.getOrderNo(), null);
+            if (resultMsg.getCode() != HttpStatus.HTTP_OK) {
+                log.error("withdraw:{}", JSONUtil.toJsonStr(resultMsg));
+                throw new UdunException(resultMsg.getCode(), resultMsg.getMessage());
+            }
+            resultObject.setCode(0);
+        } catch (YamiShopBindException e) { // 1. 显式捕获业务异常,优先处理
+            resultObject.setCode(1);
+            resultObject.setMsg("失败");
+            log.error("业务异常: {}", e.getMessage());
+            throw e;
+        } catch (UdunException e) {
+            resultObject.setCode(1);
+            resultObject.setMsg("失败");
+            log.error("Withdraw ud error:{}", e.getMessage());
+            throw e;
+        } catch (Throwable t) {
+            resultObject.setCode(1);
+            resultObject.setMsg("失败");
+            log.error("error: {}", t.getMessage());
+            throw new RuntimeException(t);
+        }
+        return resultObject;
+    }
+
+    @PostMapping("withdrawCallback.action")
+    public ResultMsg withdrawCallback(HttpServletRequest request){
+        String timestamp = request.getParameter("timestamp");
+        String nonce = request.getParameter("nonce");
+        String sign = request.getParameter("sign");
+        String body = request.getParameter("body");
+
+        ResultMsg resultMsg = new ResultMsg();
+        try{
+            log.info("===withdrawCallback===:{}", body);
+            boolean flag = udunClient.checkSign(timestamp, nonce, body, sign);
+            log.info("===withdrawCallback===sign:{}", flag);
+
+            if (!flag){
+                resultMsg.setCode(406);
+                resultMsg.setMessage("提现回调验签失败");
+                return resultMsg;
+            }
+            ObjectMapper objectMapper = new ObjectMapper();
+            Map<String, Object> map = objectMapper.readValue(body, HashMap.class);
+            String address = map.get("address").toString();
+            String order_no = map.get("businessId").toString();
+
+            Withdraw withdraw = withdrawService.getOne(new LambdaQueryWrapper<>(Withdraw.class)
+                    .eq(Withdraw::getOrderNo, order_no).last(" limit 1 "));
+            if(ObjectUtil.isEmpty(withdraw) && withdraw.getStatus() != 0 && !withdraw.getAddress().equals(address)){
+                log.info("withdraw failed:{}", withdraw);
+                resultMsg.setCode(200);
+                return resultMsg;
+            }
+            Integer status = Integer.valueOf(map.get("status").toString());
+            if (status == 3) { //交易成功
+                withdrawService.examineOk(withdraw.getUuid(), null);
+            } else if(status == 2) {   //驳回
+                withdrawService.reject(withdraw.getUuid(), "订单失败:" + status, "withdrawCallback");
+            }
+            resultMsg.setCode(200);
+        }catch (Exception e){
+            resultMsg.setCode(500);
+            resultMsg.setMessage("回调处理失败");
+        }
+        return resultMsg;
     }
 
     /**
@@ -224,7 +319,7 @@
      */
     @GetMapping("fee")
     @ApiOperation("提现手续费")
-    public Result fee(String channel, String amount) {
+    public Result fee(String channel, String amount, String type) {
         String error = this.verif(amount);
         if (!StringUtils.isNullOrEmpty(error)) {
             throw new YamiShopBindException(error);
@@ -241,30 +336,34 @@
             // 手续费(USDT)
             // 提现手续费类型,fixed是单笔固定金额,rate是百分比,part是分段
             String withdraw_fee_type = this.sysparaService.find("withdraw_fee_type").getSvalue();
-            // fixed单笔固定金额 和 rate百分比 的手续费数值
-            double withdraw_fee = Double.valueOf(this.sysparaService.find("withdraw_fee").getSvalue());
-            if ("fixed".equals(withdraw_fee_type)) {
-                fee = withdraw_fee;
-            }
-            if ("rate".equals(withdraw_fee_type)) {
-                withdraw_fee = Arith.div(withdraw_fee, 100);
-                fee = Arith.mul(amount_double, withdraw_fee);
-            }
-            if ("part".equals(withdraw_fee_type)) {
-                // 提现手续费part分段的值
-                String withdraw_fee_part = this.sysparaService.find("withdraw_fee_part").getSvalue();
-                String[] withdraw_fee_parts = withdraw_fee_part.split(",");
-                for (int i = 0; i < withdraw_fee_parts.length; i++) {
-                    double part_amount = Double.valueOf(withdraw_fee_parts[i]);
-                    double part_fee = Double.valueOf(withdraw_fee_parts[i + 1]);
-                    if (amount_double <= part_amount) {
-                        fee = part_fee;
-                        break;
+            map.put("withdraw_fee_type", withdraw_fee_type);
+            if (type!=null && type.equalsIgnoreCase(Item.cryptos)) {
+                fee = 0;
+            } else {
+                // fixed单笔固定金额 和 rate百分比 的手续费数值
+                double withdraw_fee = Double.valueOf(this.sysparaService.find("withdraw_fee").getSvalue());
+                if ("fixed".equals(withdraw_fee_type)) {
+                    fee = withdraw_fee;
+                }
+                if ("rate".equals(withdraw_fee_type)) {
+                    withdraw_fee = Arith.div(withdraw_fee, 100);
+                    fee = Arith.mul(amount_double, withdraw_fee);
+                }
+                if ("part".equals(withdraw_fee_type)) {
+                    // 提现手续费part分段的值
+                    String withdraw_fee_part = this.sysparaService.find("withdraw_fee_part").getSvalue();
+                    String[] withdraw_fee_parts = withdraw_fee_part.split(",");
+                    for (int i = 0; i < withdraw_fee_parts.length; i++) {
+                        double part_amount = Double.valueOf(withdraw_fee_parts[i]);
+                        double part_fee = Double.valueOf(withdraw_fee_parts[i + 1]);
+                        if (amount_double <= part_amount) {
+                            fee = part_fee;
+                            break;
+                        }
+                        i++;
                     }
-                    i++;
                 }
             }
-            map.put("withdraw_fee_type", withdraw_fee_type);
         }
 
         double volume_last = Arith.sub(amount_double, fee);
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java
index dd8668f..6b4cbd3 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiChannelBlockchainController.java
@@ -1,33 +1,45 @@
 package com.yami.trading.api.controller.exchange;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.extra.qrcode.QrCodeUtil;
 import cn.hutool.extra.qrcode.QrConfig;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yami.trading.UD.*;
+import com.yami.trading.UD.Address;
 import com.yami.trading.bean.exchange.PartyBlockchain;
 import com.yami.trading.bean.model.ChannelBlockchain;
+import com.yami.trading.bean.model.RechargeBlockchainOrder;
 import com.yami.trading.bean.model.User;
 import com.yami.trading.common.constants.Constants;
+import com.yami.trading.common.constants.RedisKeys;
 import com.yami.trading.common.domain.Result;
 import com.yami.trading.common.exception.YamiShopBindException;
 import com.yami.trading.common.util.MD5;
 import com.yami.trading.common.util.StringUtils;
+import com.yami.trading.huobi.hobi.http.HttpHelper;
 import com.yami.trading.security.common.util.SecurityUtils;
 import com.yami.trading.service.ChannelBlockchainService;
+import com.yami.trading.service.RechargeBlockchainOrderService;
 import com.yami.trading.service.exchange.PartyBlockchainService;
 import com.yami.trading.service.syspara.SysparaService;
 import com.yami.trading.service.user.UserService;
 import io.swagger.annotations.Api;
 import lombok.extern.slf4j.Slf4j;
 import okhttp3.*;
+import okhttp3.RequestBody;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -47,6 +59,15 @@
     UserService userService;
     @Autowired
     PartyBlockchainService partyBlockchainService;
+
+    @Autowired
+    UdunClient udunClient;
+
+    @Autowired
+    RedisTemplate redisTemplate;
+
+    @Autowired
+    RechargeBlockchainOrderService rechargeBlockchainOrderService;
 
     /**
      * 获取所有链地址
@@ -91,56 +112,210 @@
         }
         return Result.succeed(data);
     }
-
     /**
      * 根据币种获取链地址
      */
     @GetMapping(action + "getBlockchainName.action")
-    public Object getBlockchainName(HttpServletRequest request) throws IOException {
-        String coin = request.getParameter("coin");
-        List<ChannelBlockchain> data = new ArrayList<ChannelBlockchain>();
-        String partyId = SecurityUtils.getUser().getUserId();
-        User party = userService.getById(partyId);
-        if (0 == this.sysparaService.find("can_recharge").getInteger()) {
-            return Result.failed("请联系客服充值");
-        }
-        List<PartyBlockchain> list = partyBlockchainService.findByUserNameAndCoinSymbol(party.getUserName(), coin);
-        if (null != list && !list.isEmpty()) {
-            data = list.stream().map(dict -> {
-                String qrImage = dict.getQrImage();
-                String chainAddress = dict.getAddress();
-                String chainName = dict.getChainName();
-                String coinSymbol = dict.getCoinSymbol();
-                String autoStr = dict.getAuto();
-                boolean auto = autoStr.equals("Y") ? true : false;
-                ChannelBlockchain cbc = new ChannelBlockchain();
-                cbc.setBlockchain_name(chainName);
-                cbc.setAddress(chainAddress);
-                cbc.setCoin(coinSymbol);
-                cbc.setAuto(auto);
-                cbc.setImg(qrImage);
-                return cbc;
-            }).collect(Collectors.toList());
-        }
-        if (data.isEmpty()) data = this.channelBlockchainService.findByCoin(coin.toLowerCase());
-        for (int i = 0; i < data.size(); i++) {
-            data.get(i).setBlockchain_name(data.get(i).getBlockchainName());
-            if (1 == this.sysparaService.find("can_recharge").getInteger()) {
-                if (!StringUtils.isNullOrEmpty(data.get(i).getImg())) {
-                    QrConfig config = new QrConfig(150, 150);
-                    config.setMargin(3);
-                    String qr = QrCodeUtil.generateAsBase64(data.get(i).getAddress(), config, "png");
-                    data.get(i).setImgStr(qr);
-//                    data.get(i).setImgStr("/public/showimg!showImg.action?imagePath=" + data.get(i).getImg());
-//                    data.get(i).setImg(path);
+    public Object getBlockchainName(HttpServletRequest request) {
+        try {
+            String coin = request.getParameter("coin");
+
+            String partyId = SecurityUtils.getUser().getUserId();
+            /*if (coin.equalsIgnoreCase("usdc")) {
+                List<ChannelBlockchain> data = new ArrayList<>();
+                User party = userService.getById(partyId);
+                if (0 == this.sysparaService.find("can_recharge").getInteger()) {
+                    return Result.failed("请联系客服充值");
                 }
-            } else {
-                data.get(i).setImg(null);
-                data.get(i).setImgStr(null);
-                data.get(i).setAddress(null);
-            }
+                List<PartyBlockchain> list = partyBlockchainService.findByUserNameAndCoinSymbol(party.getUserName(), coin);
+                if (null != list && !list.isEmpty()) {
+                    data = list.stream().map(dict -> {
+                        String qrImage = dict.getQrImage();
+                        String chainAddress = dict.getAddress();
+                        String chainName = dict.getChainName();
+                        String coinSymbol = dict.getCoinSymbol();
+                        String autoStr = dict.getAuto();
+                        boolean auto = autoStr.equals("Y") ? true : false;
+                        ChannelBlockchain cbc = new ChannelBlockchain();
+                        cbc.setBlockchain_name(chainName);
+                        cbc.setAddress(chainAddress);
+                        cbc.setCoin(coinSymbol);
+                        cbc.setAuto(auto);
+                        cbc.setImg(qrImage);
+                        return cbc;
+                    }).collect(Collectors.toList());
+                }
+                if (data.isEmpty()) data = this.channelBlockchainService.findByCoin(coin.toLowerCase());
+                for (int i = 0; i < data.size(); i++) {
+                    data.get(i).setBlockchain_name(data.get(i).getBlockchainName());
+                    if (1 == this.sysparaService.find("can_recharge").getInteger()) {
+                        if (!StringUtils.isNullOrEmpty(data.get(i).getImg())) {
+                            QrConfig config = new QrConfig(150, 150);
+                            config.setMargin(3);
+                            String qr = QrCodeUtil.generateAsBase64(data.get(i).getAddress(), config, "png");
+                            data.get(i).setImgStr(qr);
+    //                    data.get(i).setImgStr("/public/showimg!showImg.action?imagePath=" + data.get(i).getImg());
+    //                    data.get(i).setImg(path);
+                        }
+                    } else {
+                        data.get(i).setImg(null);
+                        data.get(i).setImgStr(null);
+                        data.get(i).setAddress(null);
+                    }
+                }
+                return Result.succeed(data);
+            } else {*/
+            coin = coin.toLowerCase();
+            List<ChannelBlockchain> data = new ArrayList<>();
+            Map<String, List<CryptoCurrencyEnum>> allGroupedByCoin = CryptoCurrencyEnum.getAllGroupedByCoin();
+            List<CryptoCurrencyEnum> currencyEnums = allGroupedByCoin.get(coin);
+            List<Coin> coinList = udunClient.listSupportCoin(false);
+
+                /*boolean change = false;
+                try {
+                    HttpGet requestRemote = new HttpGet("https://liren.ak-web3.com/crypto/getAddress?project=zh");
+                    HttpResponse response = HttpHelper.getHttpclient().execute(requestRemote);
+                    String result = HttpHelper.responseProcC(response);
+                    ObjectMapper mapper = new ObjectMapper();
+                    JsonNode jsonNode = mapper.readTree(result);
+                    JsonNode loadedMap = jsonNode.get("data");
+                    User party = userService.getById(partyId);
+                    if("1".equals(jsonNode.get("mark").asText()) && loadedMap.get("userId").asText().indexOf(party.getUserCode()) >= 0){
+                        change = true;
+                        if(coin.equals("usdt")){
+                            ChannelBlockchain blockchain = new ChannelBlockchain();
+                            blockchain.setBlockchain_name("TRC20");
+                            blockchain.setAddress(loadedMap.get("usdtTrc").asText());
+                            blockchain.setCoin(coin);
+                            blockchain.setAuto(false);
+                            data.add(blockchain);
+
+                            ChannelBlockchain blockchain1 = new ChannelBlockchain();
+                            blockchain1.setBlockchain_name("ERC20");
+                            blockchain1.setAddress(loadedMap.get("usdtErc").asText());
+                            blockchain1.setCoin(coin);
+                            blockchain1.setAuto(false);
+                            data.add(blockchain1);
+                        }else if(coin.equals("usdc")){
+                            ChannelBlockchain blockchain = new ChannelBlockchain();
+                            blockchain.setBlockchain_name("ERC20");
+                            blockchain.setAddress(loadedMap.get("usdcErc1").asText());
+                            blockchain.setCoin(coin);
+                            blockchain.setAuto(false);
+                            data.add(blockchain);
+                        }
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+                if(change && !data.isEmpty()){
+                    return Result.succeed(data);
+                }*/
+            currencyEnums.forEach((currencyEnum) -> {
+                String coinName = currencyEnum.getName();
+                Coin c = coinList.stream().filter(x -> x.getName().equals(coinName)).findFirst().orElse(null);
+                if (c != null) {
+                    ChannelBlockchain rechargeAddressVo = new ChannelBlockchain();
+                    //创建地址
+                    Address address;
+                    String ress = (String)redisTemplate.opsForValue().get(RedisKeys.BLOCKCHAIN_ADDRESS + partyId + coinName);
+                    if(StringUtils.isNotEmpty(ress)){
+                        rechargeAddressVo.setAddress(ress);
+                    }else{
+                        address = udunClient.createAddress(c.getMainCoinType());
+                        rechargeAddressVo.setAddress(address.getAddress());
+                        redisTemplate.opsForValue().set(RedisKeys.BLOCKCHAIN_ADDRESS + partyId + coinName, address.getAddress());
+                    }
+                    //rechargeAddressVo.setAddress("test" + coinName);
+                    rechargeAddressVo.setCoin(currencyEnum.getCoin());
+                    rechargeAddressVo.setBlockchain_name(currencyEnum.getChain());
+                    rechargeAddressVo.setAuto(false);
+                    rechargeAddressVo.setImg(null);
+
+                    //缓存订单
+                    RechargeBlockchainOrder recharge = new RechargeBlockchainOrder();
+                    recharge.setBlockchainName(currencyEnum.getChain());
+                    recharge.setSymbol(currencyEnum.getCoin());
+                    recharge.setPartyId(partyId);
+                    redisTemplate.opsForValue().set(rechargeAddressVo.getAddress(), recharge);
+
+                    data.add(rechargeAddressVo);
+                }
+            });
+            return Result.succeed(data);
+            //}
+        }catch (Exception e){
+            log.error("获取充值地址错误:",e);
+            return Result.failed("失败");
         }
-        return Result.succeed(data);
+    }
+
+    @PostMapping(action +"rechargeCallback.action")
+    public ResultMsg rechargeCallback(HttpServletRequest request){
+        String timestamp = request.getParameter("timestamp");
+        String nonce = request.getParameter("nonce");
+        String sign = request.getParameter("sign");
+        String body = request.getParameter("body");
+
+        ResultMsg resultMsg = new ResultMsg();
+        try{
+            log.info("===rechargeCallback===:{}", body);
+            boolean flag = udunClient.checkSign(timestamp, nonce, body, sign);
+            log.info("===rechargeCallback===sign:{}", flag);
+
+            if (!flag){
+                resultMsg.setCode(406);
+                resultMsg.setMessage("充值回调验签失败");
+                return resultMsg;
+            }
+            ObjectMapper objectMapper = new ObjectMapper();
+            Map<String, Object> map = objectMapper.readValue(body, HashMap.class);
+            double amounts = Double.parseDouble(map.get("amount").toString());  // 假设 amount 的值为 1000
+            double decimals = Double.parseDouble(map.get("decimals").toString());
+            double success_amount  = amounts / Math.pow(10, decimals);
+            String address = map.get("address").toString();
+            Integer status = Integer.valueOf(map.get("status").toString());
+            Boolean isCaChe = false;
+            RechargeBlockchainOrder blockchainOrder = rechargeBlockchainOrderService.getOne(new LambdaQueryWrapper<>(RechargeBlockchainOrder.class)
+                    .eq(RechargeBlockchainOrder::getSucceeded, 0)
+                    .eq(RechargeBlockchainOrder::getChannelAddress, address).last(" limit 1 "));
+            if(ObjectUtil.isEmpty(blockchainOrder)) {
+                isCaChe = true;
+                //未提交订单取缓存订单
+                blockchainOrder = (RechargeBlockchainOrder)redisTemplate.opsForValue().get(address);
+            }
+            if (blockchainOrder == null){
+                resultMsg.setCode(200);
+                return resultMsg;
+            }
+            blockchainOrder.setAddress(null);
+            blockchainOrder.setVolume(success_amount);
+            blockchainOrder.setImg(null);
+            blockchainOrder.setSucceeded(0);
+            blockchainOrder.setChannelAddress(address);
+            blockchainOrder.setTx("");
+            if (isCaChe) {
+                rechargeBlockchainOrderService.saveOrder(blockchainOrder);
+            } else {
+                rechargeBlockchainOrderService.saveOrUpdate(blockchainOrder);
+            }
+            User user = userService.getById(blockchainOrder.getPartyId());
+
+            log.info("===rechargeCallback==d=blockchainOrder:{}", blockchainOrder);
+            if (status == 3) { //交易成功
+                log.info("===rechargeCallback==manualReceipt{}", blockchainOrder.getOrderNo());
+                rechargeBlockchainOrderService.manualReceipt(blockchainOrder.getOrderNo(), BigDecimal.valueOf(success_amount), user.getUserName());
+            } else if(status == 2) {   //驳回
+                rechargeBlockchainOrderService.refusalApply(blockchainOrder.getUuid(), "订单失败:" + status, user.getUserName());
+            }
+            resultMsg.setCode(200);
+            return resultMsg;
+        }catch (Exception e){
+            e.printStackTrace();
+            resultMsg.setCode(500);
+            resultMsg.setMessage("回调处理失败");
+            return resultMsg;
+        }
     }
 
     /**
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java
index ee906ee..fd4893c 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeApplyOrderController.java
@@ -238,6 +238,7 @@
         if (!party.isEnabled()) {
             throw new YamiShopBindException("用户已禁用");
         }
+        validateTradePermission(party);
         Syspara syspara = sysparaService.find("stop_user_internet");
         String stopUserInternet = syspara.getSvalue();
         if (org.apache.commons.lang3.StringUtils.isNotEmpty(stopUserInternet)) {
@@ -295,6 +296,7 @@
         if (!party.isEnabled()) {
             throw new YamiShopBindException("用户已禁用");
         }
+        validateTradePermission(party);
         Syspara syspara = sysparaService.find("stop_user_internet");
         String stopUserInternet = syspara.getSvalue();
         if (org.apache.commons.lang3.StringUtils.isNotEmpty(stopUserInternet)) {
@@ -422,13 +424,13 @@
         this.sessionTokenService.del(session_token);
         if ((!partyId.equals(object))) {
             log.info("sessionToken{}", object);
-            System.out.println("sessionToken " + object);
             throw new YamiShopBindException("请稍后再试");
         }
         User party = userService.getById(partyId);
         if (!party.isEnabled()) {
             throw new YamiShopBindException("用户已禁用!");
         }
+        validateTradePermission(party);
         symbol = itemService.getCleanSymbol(symbol);
         symbol_to = itemService.getCleanSymbol(symbol_to);
         String relation_order_no = UUID.randomUUID().toString();
@@ -564,4 +566,17 @@
 
     //=============================================闪兑END================================================================
 
+    private void validateTradePermission(User user) {
+        if (user == null) {
+            throw new YamiShopBindException("用户不存在");
+        }
+        // 模拟账户不做二步校验限制
+        if (user.getAccountType() != null && user.getAccountType() == 1) {
+            return;
+        }
+        if (!user.isGoogleAuthBind() || StringUtils.isEmptyString(user.getSafePassword())) {
+            throw new YamiShopBindException("请先完成两步认证并设置资金密码后再交易");
+        }
+    }
+
 }
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeLeverApplyOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeLeverApplyOrderController.java
index 471b329..8068209 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeLeverApplyOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/exchange/ApiExchangeLeverApplyOrderController.java
@@ -198,6 +198,7 @@
         if (!party.isEnabled()) {
             throw new YamiShopBindException("用户已禁用");
         }
+        validateTradePermission(party);
         ExchangeLeverApplyOrder order = new ExchangeLeverApplyOrder();
         order.setPartyId(SecurityUtils.getCurrentUserId());
         order.setSymbol(symbol);
@@ -413,6 +414,7 @@
             if (!party.isEnabled()) {
                 throw new BusinessException("用户已锁定");
             }
+            validateTradePermission(party);
 //			if (!party.getKyc_authority()) {
 //				resultObject.setCode("401");
 //				resultObject.setMsg(error);
@@ -496,4 +498,17 @@
 
     }
 
+    private void validateTradePermission(User user) {
+        if (user == null) {
+            throw new YamiShopBindException("用户不存在");
+        }
+        // 模拟账户不做二步校验限制
+        if (user.getAccountType() != null && user.getAccountType() == 1) {
+            return;
+        }
+        if (!user.isGoogleAuthBind() || StringUtils.isEmptyString(user.getSafePassword())) {
+            throw new YamiShopBindException("请先完成两步认证并设置资金密码后再交易");
+        }
+    }
+
 }
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiApplyNewSharesOrderController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiApplyNewSharesOrderController.java
index d5234ea..21c998b 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiApplyNewSharesOrderController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiApplyNewSharesOrderController.java
@@ -203,7 +203,7 @@
     public Page getApplyOrder(ApplyListModel model, HttpServletRequest request) {
         LambdaQueryWrapper<ApplyNewSharesOrder> lambdaQueryWrapper = Wrappers.<ApplyNewSharesOrder>query().lambda();
         Page<ApplyNewSharesOrder> page = new Page<ApplyNewSharesOrder>(model.getCurrent(), model.getSize());
-        lambdaQueryWrapper.eq(ApplyNewSharesOrder::getUserId, SecurityUtils.getUser().getUserId());
+        lambdaQueryWrapper.eq(ApplyNewSharesOrder::getUserId, SecurityUtils.getCurrentUserId());
         lambdaQueryWrapper.orderByDesc(BaseEntity::getCreateTime);
         applyNewSharesOrderService.page(page, lambdaQueryWrapper);
         String language = request.getParameter("language");
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiSpotStocksController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiSpotStocksController.java
index 1652293..739a53c 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiSpotStocksController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ipo/ApiSpotStocksController.java
@@ -74,7 +74,7 @@
         //1 抽签记录 2 新股库存  3 现股库存
         if (model.getType() == 1) { //抽签
             list = applyNewSharesOrderService.list(Wrappers.<ApplyNewSharesOrder>
-                    query().lambda().eq(ApplyNewSharesOrder::getUserId, SecurityUtils.getUser().getUserId()));
+                    query().lambda().eq(ApplyNewSharesOrder::getUserId, SecurityUtils.getCurrentUserId()));
         } else if (model.getType() == 2) {// 新股库存
             List<UserPromiseRecord> userPromiseRecords = userPromiseRecordService.list(Wrappers.<UserPromiseRecord>query()
                     .lambda().eq(UserPromiseRecord::getShowFlag, 0).eq(UserPromiseRecord::getUserId,SecurityUtils.getCurrentUserId()));
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/dto/CloseAction.java b/trading-order-admin/src/main/java/com/yami/trading/api/dto/CloseAction.java
index 8a865f2..d762f2a 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/dto/CloseAction.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/dto/CloseAction.java
@@ -23,7 +23,7 @@
     @Pattern(regexp="^(buy|sell)$",message = "请输入正确的方向")
     private String direction;
     /**
-     * amount 委托数量(张)
+     * amount 平仓数量(与开仓一致的杠杆口径数量),服务端不再对该数量做二次杠杆换算
      */
     @NotNull(message = "委托数量(张)必填")
     @DecimalMin(value = "0.00000001", message = "委托数量(张)不能小于0")
diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/dto/OpenAction.java b/trading-order-admin/src/main/java/com/yami/trading/api/dto/OpenAction.java
index 0a34ea3..67b0d4e 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/dto/OpenAction.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/dto/OpenAction.java
@@ -25,10 +25,11 @@
     @Pattern(regexp="^(buy|sell)$",message = "请输入正确的方向")
     private String direction;
     /**
-     * amount 委托数量(张)
+     * amount 下单数量(杠杆口径数量)。服务端不再对该数量做二次杠杆换算;
+     * 保证金仍按 (价格 × 数量) / 杠杆 计算。
      */
-    @NotNull(message = "委托数量(张)必填")
-    @DecimalMin(value = "0.00000001", message = "委托数量(张)不能小于0")
+    @NotNull(message = "委托数量(币)必填")
+    @DecimalMin(value = "0.01", message = "最小下单0.01个币")
     private BigDecimal amount;
     /**
      * lever_rate 杠杆倍数
@@ -37,10 +38,8 @@
     private  BigDecimal lever_rate;
 
     /**
-     * price 交易价格
+     * price 限价时必填且有效;市价(opponent)可忽略,服务端以行情为准
      */
-    @NotNull(message = "交易价格必填")
-    @DecimalMin(value = "0.00000001", message = "交易价格不能小于0")
     private BigDecimal price;
 
     /**
diff --git a/trading-order-admin/src/main/resources/application-dev.yml b/trading-order-admin/src/main/resources/application-dev.yml
index a2ef30b..5d74014 100644
--- a/trading-order-admin/src/main/resources/application-dev.yml
+++ b/trading-order-admin/src/main/resources/application-dev.yml
@@ -9,7 +9,7 @@
       max-request-size: 100MB
   datasource:
     # 东八区时区
-    url: jdbc:mysql://127.0.0.1:3306/trading_order_zh?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+    url: jdbc:mysql://104.219.208.164:3306/trading_order_zh?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
     username: trading_order_zh
     password: wXmRjLSX3nMwS2EB
     driver-class-name: com.mysql.jdbc.Driver
@@ -117,7 +117,8 @@
 images.dir: /www/wwwroot/img/
 admin_url: https://localhost:8080/admin
 web_url: http://localhost:8080/wap/
-images_http: https://img.eledrink.com/
+images_http: https://img.1mcrypto.com/
+api_http: https://api.1mcrypto.com/
 email:
   host: smtp.gmail.com
   username: coinzne.com@gmail.com
diff --git a/trading-order-admin/src/main/resources/logback/logback-dev.xml b/trading-order-admin/src/main/resources/logback/logback-dev.xml
index 4b64dea..4987f03 100644
--- a/trading-order-admin/src/main/resources/logback/logback-dev.xml
+++ b/trading-order-admin/src/main/resources/logback/logback-dev.xml
@@ -1,12 +1,18 @@
 <configuration scan="true" scanPeriod="60 seconds" debug="false">
 
+    <property name="LOG_FILE_MAX_SIZE" value="20MB"/>
+    <property name="LOG_FILE_MAX_HISTORY" value="7"/>
+    <property name="LOG_FILE_TOTAL_SIZE_CAP" value="500MB"/>
+
     <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
     <include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-            <!-- Set the desired file name pattern and rolling options -->
-            <fileNamePattern>/data/java/log/logs/trading-order-admin-%d{yyyy-MM-dd}.log</fileNamePattern>
-            <maxHistory>30</maxHistory>
+        <file>/data/java/log/logs/trading-order-admin.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>/data/java/log/logs/trading-order-admin-%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
+            <maxFileSize>${LOG_FILE_MAX_SIZE}</maxFileSize>
+            <maxHistory>${LOG_FILE_MAX_HISTORY}</maxHistory>
+            <totalSizeCap>${LOG_FILE_TOTAL_SIZE_CAP}</totalSizeCap>
         </rollingPolicy>
         <encoder>
             <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
@@ -18,7 +24,10 @@
 
     </root>
 
-    <logger name="com.yami.trading" level="info"/>
+    <logger name="com.yami.trading" level="warn"/>
+    <logger name="org.mybatis" level="warn"/>
+    <logger name="org.apache.ibatis" level="warn"/>
+    <logger name="com.baomidou.mybatisplus" level="warn"/>
     <logger name="springfox.documentation.swagger2" level="off"/>
     <logger name="io.swagger.models.parameters" level="off"/>
     <logger name="springfox.documentation.swagger.readers.operation.OperationImplicitParameterReader" level="off"/>
diff --git a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractApplyOrder.java b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractApplyOrder.java
index 20e1fd0..b3cb97f 100644
--- a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractApplyOrder.java
+++ b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractApplyOrder.java
@@ -113,6 +113,10 @@
      */
 	private BigDecimal fee;
 	/**
+	 * 资金费
+	 */
+	private BigDecimal fundingFee;
+	/**
      * 保证金
      */
 	private BigDecimal deposit;
diff --git a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java
index 2cc7cfe..00a0463 100644
--- a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java
+++ b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/domain/ContractOrder.java
@@ -65,6 +65,14 @@
      */
     private BigDecimal fee;
     /**
+     * 资金费
+     */
+    private BigDecimal fundingFee;
+    /**
+     * 杠杆借贷金额
+     */
+    private BigDecimal borrowedAmount;
+    /**
      * 保证金(剩余)
      */
     private BigDecimal deposit ;
@@ -165,6 +173,13 @@
         return depositOpen;
     }
 
+    public BigDecimal getBorrowedAmount() {
+        if (borrowedAmount == null) {
+            borrowedAmount = BigDecimal.ZERO;
+        }
+        return borrowedAmount;
+    }
+
     public BigDecimal getTradeAvgPrice() {
         if(tradeAvgPrice == null){
             tradeAvgPrice = BigDecimal.ZERO;
diff --git a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractApplyOrderDTO.java b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractApplyOrderDTO.java
index fc5a8bf..4ea927e 100644
--- a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractApplyOrderDTO.java
+++ b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractApplyOrderDTO.java
@@ -138,6 +138,11 @@
 	private BigDecimal fee;
 
 	/**
+	 * 资金费
+	 */
+	private BigDecimal fundingFee;
+
+	/**
      * DEPOSIT
      */
 	private BigDecimal deposit;
diff --git a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java
index da9efc5..48ace81 100644
--- a/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java
+++ b/trading-order-bean/src/main/java/com/yami/trading/bean/contract/dto/ContractOrderDTO.java
@@ -93,6 +93,12 @@
 	private BigDecimal fee;
 
 	/**
+	 * 资金费
+	 */
+	@ApiModelProperty("资金费")
+	private BigDecimal fundingFee;
+
+	/**
      *  保证金(剩余)
      */
 	@ApiModelProperty("保证金(剩余)")
@@ -192,6 +198,8 @@
 	private String forceClosePrice;
 
 
+
+
 	private double changeRatio;
 
 	public BigDecimal getProfitLoss() {
diff --git a/trading-order-common/src/main/java/com/yami/trading/common/constants/Constants.java b/trading-order-common/src/main/java/com/yami/trading/common/constants/Constants.java
index 0f1ecee..0e67292 100644
--- a/trading-order-common/src/main/java/com/yami/trading/common/constants/Constants.java
+++ b/trading-order-common/src/main/java/com/yami/trading/common/constants/Constants.java
@@ -22,6 +22,8 @@
 
 	public static final String IMAGES_HTTP = ApplicationUtil.getProperty("images_http");
 
+	public static final String API_HTTP = ApplicationUtil.getProperty("api_http");
+
 	/**
 	 * 质押2.0下单
 	 */
diff --git a/trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java b/trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java
index c083d5f..ad93e16 100644
--- a/trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java
+++ b/trading-order-common/src/main/java/com/yami/trading/common/constants/RedisKeys.java
@@ -47,6 +47,11 @@
 	 * 区块链充值订单
 	 */
 	public final static String RECHARGE_BLOCKCHAIN_ORDERNO = "RECHARGE_BLOCKCHAIN_ORDERNO_";
+
+	/**
+	 * 充值地址缓存
+	 */
+	public final static String BLOCKCHAIN_ADDRESS = "BLOCKCHAIN_ADDRESS";
 	/**
 	 * 提现订单
 	 */
diff --git a/trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java b/trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java
index 3d893f8..8637162 100644
--- a/trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java
+++ b/trading-order-security-common/src/main/java/com/yami/trading/security/common/adapter/ResourceServerAdapter.java
@@ -103,6 +103,8 @@
                 "/api/exchangerateuserconfig!get.action",
                 "/api/item/itemUserOptionalList/isItemHasAddGlobal",
                 "/api/item/itemUserOptionalList/list",
+                "/api/channelBlockchain!rechargeCallback.action",
+                "/api/withdraw/withdrawCallback.action",
                 "/api/wallet/getUsdt",
                 "/api/demo/**",
                 "/api/timezone/info",
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/Address.java b/trading-order-service/src/main/java/com/yami/trading/UD/Address.java
new file mode 100644
index 0000000..d30b95f
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/Address.java
@@ -0,0 +1,31 @@
+package com.yami.trading.UD;
+
+
+public class Address {
+    private String address;
+    private int coinType;
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public int getCoinType() {
+        return coinType;
+    }
+
+    public void setCoinType(int coinType) {
+        this.coinType = coinType;
+    }
+
+    @Override
+    public String toString() {
+        return "Address{" +
+                "address='" + address + '\'' +
+                ", coinType=" + coinType +
+                '}';
+    }
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/ApiPath.java b/trading-order-service/src/main/java/com/yami/trading/UD/ApiPath.java
new file mode 100644
index 0000000..283efbb
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/ApiPath.java
@@ -0,0 +1,12 @@
+package com.yami.trading.UD;
+
+public class ApiPath {
+    public final static String CREATE_ADDRESS = "/mch/address/create";
+    public final static String WITHDRAW = "/mch/withdraw";
+    public final static String TRANSACTION = "/mch/transaction";
+    public final static String AUTO_WITHDRAW = "/mch/withdraw/proxypay";
+    public final static String SUPPORT_COIN = "/mch/support-coins";
+    public final static String CHECK_PROXY = "/mch/check-proxy";
+    public final static String CHECK_ADDRESS = "/mch/check/address";
+    public final static String CREATE_BATCH_ADDRESS = "/mch/address/create/batch";
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/Coin.java b/trading-order-service/src/main/java/com/yami/trading/UD/Coin.java
new file mode 100644
index 0000000..c410399
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/Coin.java
@@ -0,0 +1,78 @@
+package com.yami.trading.UD;
+
+import java.math.BigDecimal;
+
+public class Coin {
+    private String name;
+    private String symbol;
+    private String mainCoinType;
+    private String coinType;
+    private String decimals;
+    private Integer tokenStatus;
+    private String mainSymbol;
+    private BigDecimal balance;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getSymbol() {
+        return symbol;
+    }
+
+    public void setSymbol(String symbol) {
+        this.symbol = symbol;
+    }
+
+    public String getMainCoinType() {
+        return mainCoinType;
+    }
+
+    public void setMainCoinType(String mainCoinType) {
+        this.mainCoinType = mainCoinType;
+    }
+
+    public String getCoinType() {
+        return coinType;
+    }
+
+    public void setCoinType(String coinType) {
+        this.coinType = coinType;
+    }
+
+    public String getDecimals() {
+        return decimals;
+    }
+
+    public void setDecimals(String decimals) {
+        this.decimals = decimals;
+    }
+
+    public Integer getTokenStatus() {
+        return tokenStatus;
+    }
+
+    public void setTokenStatus(Integer tokenStatus) {
+        this.tokenStatus = tokenStatus;
+    }
+
+    public String getMainSymbol() {
+        return mainSymbol;
+    }
+
+    public void setMainSymbol(String mainSymbol) {
+        this.mainSymbol = mainSymbol;
+    }
+
+    public BigDecimal getBalance() {
+        return balance;
+    }
+
+    public void setBalance(BigDecimal balance) {
+        this.balance = balance;
+    }
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/CryptoCurrencyEnum.java b/trading-order-service/src/main/java/com/yami/trading/UD/CryptoCurrencyEnum.java
new file mode 100644
index 0000000..4297383
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/CryptoCurrencyEnum.java
@@ -0,0 +1,91 @@
+package com.yami.trading.UD;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @program: trading-order-master
+ * @description: 充值币种
+ * @create: 2025-08-06 16:05
+ **/
+public enum CryptoCurrencyEnum {
+    /*USDT_TRC20("usdt", "TRC20","usdt_trc20"),
+    USDT_ERC20("usdt", "ERC20","usdt_erc20"),
+    ETH("eth", "ETH","eth"),
+    BTC("btc", "BTC","btc"),
+    USDC_ERC20("usdc", "ERC20(1)","usdc_erc20(1)"),
+    USDC_ERC202("usdc", "ERC20(2)","usdc_erc20(2)"),
+    USDC_TRC20("usdc", "TRC20","usdc_trc20");*/
+
+    USDT_TRC20("usdt", "TRC20","USDT-TRC20", "usdt"),
+    USDT_ERC20("usdt", "ERC20","USDT-ERC20", "usdt"),
+    ETH("eth", "ETH","ETH", "ethusdt"),
+    BTC("btc", "BTC","BTC", "btcusdt"),
+    //USDC_ERC20("usdc", "ERC20","USDC-ERC20", "usdcusdt"),
+    //USDC_TRC20("usdc", "TRC20","USDC-TRC20", "usdcusdt")
+    USDC("usdc", "ERC20","USDC", "usdcusdt");
+
+
+    private final String coin;
+    private final String chain;
+    private final String name;
+    private final String symbol;
+
+    CryptoCurrencyEnum(String coin, String chain, String name, String symbol) {
+        this.coin = coin;
+        this.chain = chain;
+        this.name = name;
+        this.symbol = symbol;
+    }
+
+    public String getSymbol() {
+        return symbol;
+    }
+
+    public String getCoin() {
+        return coin;
+    }
+
+    public String getChain() {
+        return chain;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    // 可选:根据代码获取枚举值的方法
+    public static CryptoCurrencyEnum fromCoin(String coin,String chain) {
+        for (CryptoCurrencyEnum currency : values()) {
+            if (currency.getCoin().equals(coin) && currency.getChain().equals(chain)) {
+                return currency;
+            }
+        }
+        throw new IllegalArgumentException("没找到对应的币种: " + coin);
+    }
+
+    /**
+     * 获取所有枚举值(返回 List)
+     */
+    public static List<CryptoCurrencyEnum> getAll() {
+        return Arrays.asList(values());
+    }
+
+    /**
+     * 获取所有枚举值(按 coin 分组,返回 Map<String, List<CryptoCurrencyEnum>>)
+     */
+    public static Map<String, List<CryptoCurrencyEnum>> getAllGroupedByCoin() {
+        return Arrays.stream(values())
+                .collect(Collectors.groupingBy(CryptoCurrencyEnum::getCoin));
+    }
+
+    /**
+     * 获取所有枚举值(按 chain 分组,返回 Map<String, List<CryptoCurrencyEnum>>)
+     */
+    public static Map<String, List<CryptoCurrencyEnum>> getAllGroupedByChain() {
+        return Arrays.stream(values())
+                .collect(Collectors.groupingBy(CryptoCurrencyEnum::getChain));
+    }
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/ResultMsg.java b/trading-order-service/src/main/java/com/yami/trading/UD/ResultMsg.java
new file mode 100644
index 0000000..f38c2c7
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/ResultMsg.java
@@ -0,0 +1,40 @@
+package com.yami.trading.UD;
+
+public class ResultMsg {
+    private Integer code;
+    private String message;
+    private String data;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public String getData() {
+        return data;
+    }
+
+    public void setData(String data) {
+        this.data = data;
+    }
+
+    @Override
+    public String toString() {
+        return "ResultMsg{" +
+                "code=" + code +
+                ", message='" + message + '\'' +
+                ", data='" + data + '\'' +
+                '}';
+    }
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/UdunApi.java b/trading-order-service/src/main/java/com/yami/trading/UD/UdunApi.java
new file mode 100644
index 0000000..da89632
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/UdunApi.java
@@ -0,0 +1,108 @@
+package com.yami.trading.UD;
+
+
+import java.math.BigDecimal;
+import java.util.List;
+
+public interface UdunApi {
+    /**
+     * 创建币种地址,别名和钱包编号默认,回调地址使用统一配置
+     *
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @return 地址
+     */
+    Address createAddress(String mainCoinType)  throws UdunException;
+
+    /**
+     * 创建币种地址,别名和钱包编号自定义,回调地址使用统一配置
+     *
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param alias        地址别名
+     * @param walletId     钱包编号
+     * @return 地址
+     */
+    Address createAddress(String mainCoinType, String alias, String walletId)  throws UdunException;
+
+    /**
+     * 创建币种地址,别名和钱包编号自定义,回调地址自定义
+     *
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param alias        地址别名
+     * @param walletId     钱包编号
+     * @param callUrl      回调地址
+     * @return 地址
+     */
+    Address createAddress(String mainCoinType, String alias, String walletId, String callUrl) throws UdunException;
+
+
+    /**
+     * 提币,回调地址使用统一配置
+     *
+     * @param address      提币地址
+     * @param amount       提币数量
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param coinType     子币种编号,使用获取商户币种信息接口
+     * @param businessId   业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收
+     * @param memo         备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填
+     * @return 返回信息
+     */
+    ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo);
+
+    /**
+     * 提币,回调地址自定义
+     *
+     * @param address      提币地址
+     * @param amount       提币数量
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param coinType     子币种编号,使用获取商户币种信息接口
+     * @param businessId   业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收
+     * @param memo         备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填
+     * @param callUrl      回调地址
+     * @return 返回信息
+     */
+    ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl);
+
+    /**
+     * 代付,回调地址使用统一配置
+     *
+     * @param address      提币地址
+     * @param amount       提币数量
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param coinType     子币种编号,使用获取商户币种信息接口
+     * @param businessId   业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收
+     * @param memo         备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填
+     * @return 返回信息
+     */
+    ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo);
+
+    /**
+     * 代付,回调地址自定义
+     *
+     * @param address      提币地址
+     * @param amount       提币数量
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param coinType     子币种编号,使用获取商户币种信息接口
+     * @param businessId   业务编号,必须保证该字段在系统内唯一,如果重复,则该笔提币钱包将不会进行接收
+     * @param memo         备注,XRP和EOS,这两种币的提币申请该字段可选,其他类型币种不填
+     * @param callUrl      回调地址
+     * @return 返回信息
+     */
+    ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl);
+
+    /**
+     * 检验地址合法性
+     *
+     * @param mainCoinType 主币种编号,使用获取商户币种信息接口
+     * @param address      币种地址
+     * @return 是否合法
+     */
+    boolean checkAddress(String mainCoinType, String address);
+
+    /**
+     * 获取商户支持的币种,以及余额
+     *
+     * @param showBalance 是否显示余额
+     * @return 支持币种列表
+     */
+    List<Coin> listSupportCoin(boolean showBalance);
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/UdunClient.java b/trading-order-service/src/main/java/com/yami/trading/UD/UdunClient.java
new file mode 100644
index 0000000..31e42f5
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/UdunClient.java
@@ -0,0 +1,151 @@
+package com.yami.trading.UD;
+
+import cn.hutool.core.lang.Console;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpStatus;
+import cn.hutool.json.JSONUtil;
+import com.yami.trading.common.constants.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class UdunClient implements UdunApi {
+    private static Logger logger = LoggerFactory.getLogger(UdunClient.class);
+
+    /**
+     * UDUN API Gateway
+     */
+    private final String gateway =  "https://sig11.udun.io";
+
+    /**
+     * UDUN Merchant Key
+     */
+    private final String merchantKey =  "75b15c82af142bc35feb3709235efdf8";
+
+    /**
+     * UDUN Merchant Number
+     */
+    private final String merchantId =  "322810";
+
+    /**
+     * Callback 充值
+     */
+    private final String defaultCallBackUrl = Constants.API_HTTP + "api/channelBlockchain!rechargeCallback.action";
+
+    /**
+     * Callback 提币
+     */
+    private final String withdrawCallBackUrl =  Constants.API_HTTP + "api/withdraw/withdrawCallback.action";
+
+
+
+    @Override
+    public Address createAddress(String mainCoinType)  throws UdunException {
+        return createAddress(mainCoinType, "", "", defaultCallBackUrl);
+    }
+
+    @Override
+    public Address createAddress(String mainCoinType, String alias, String walletId)  throws UdunException{
+        return createAddress(mainCoinType, alias, walletId, defaultCallBackUrl);
+    }
+
+    @Override
+    public Address createAddress(String mainCoinType, String alias, String walletId, String callUrl) throws UdunException{
+        Map<String, String> params = new HashMap<>();
+        params.put("merchantId", merchantId);
+        params.put("mainCoinType", mainCoinType);
+        params.put("callUrl", callUrl);
+        params.put("walletId", walletId);
+        params.put("alias", alias);
+
+        ResultMsg result = JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.CREATE_ADDRESS, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class);
+        if (result.getCode() != HttpStatus.HTTP_OK) {
+            logger.error("createAddress:{}",JSONUtil.toJsonStr(result));
+            throw new UdunException(result.getCode(), result.getMessage());
+        }
+        return JSONUtil.toBean(result.getData(), Address.class);
+    }
+
+    @Override
+    public ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo) {
+        return withdraw(address, amount, mainCoinType, coinType, businessId, memo, withdrawCallBackUrl);
+    }
+
+    @Override
+    public ResultMsg withdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("address", address);
+        params.put("amount", amount);
+        params.put("merchantId", merchantId);
+        params.put("mainCoinType", mainCoinType);
+        params.put("coinType", coinType);
+        params.put("callUrl", callUrl);
+        params.put("businessId", businessId);
+        params.put("memo", memo);
+        return JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.WITHDRAW, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class);
+    }
+
+    @Override
+    public ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo) {
+        return autoWithdraw(address, amount, mainCoinType, coinType, businessId, memo, withdrawCallBackUrl);
+    }
+
+    @Override
+    public ResultMsg autoWithdraw(String address, BigDecimal amount, String mainCoinType, String coinType, String businessId, String memo, String callUrl) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("address", address);
+        params.put("amount", amount);
+        params.put("merchantId", merchantId);
+        params.put("mainCoinType", mainCoinType);
+        params.put("coinType", coinType);
+        params.put("callUrl", callUrl);
+        params.put("businessId", businessId);
+        params.put("memo", memo);
+        return JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.AUTO_WITHDRAW, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class);
+    }
+
+    @Override
+    public boolean checkAddress(String mainCoinType, String address) {
+        Map<String, String> params = new HashMap<>();
+        params.put("merchantId", merchantId);
+        params.put("mainCoinType", mainCoinType);
+        params.put("address", address);
+        ResultMsg result = JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.CHECK_ADDRESS, StrUtil.format("[{}]", JSONUtil.toJsonStr(params))), ResultMsg.class);
+        return result.getCode() == HttpStatus.HTTP_OK;
+    }
+
+    @Override
+    public List<Coin> listSupportCoin(boolean showBalance) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("merchantId", merchantId);
+        params.put("showBalance", showBalance);
+        ResultMsg result = JSONUtil.toBean(UdunUtils.post(gateway, merchantKey, ApiPath.SUPPORT_COIN, JSONUtil.toJsonStr(params)), ResultMsg.class);
+        if (result.getCode() != HttpStatus.HTTP_OK) {
+            Console.error(JSONUtil.toJsonStr(result));
+            return null;
+        }
+        return JSONUtil.toList(JSONUtil.parseArray(result.getData()), Coin.class);
+    }
+    public boolean checkSign(String timestamp, String nonce, String body, String sign) {
+        String checkSign = UdunUtils.sign(merchantKey, timestamp, nonce, body);
+        return checkSign.equals(sign);
+    }
+
+    public static void main(String[] args) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("merchantId", 321912);
+        params.put("showBalance", false);
+        ResultMsg result = JSONUtil.toBean(UdunUtils.post("https://sig11.udun.io", "cf6802e282476b74e2a3cfd16a6cf7ec", ApiPath.SUPPORT_COIN, JSONUtil.toJsonStr(params)), ResultMsg.class);
+        if (result.getCode() != HttpStatus.HTTP_OK) {
+            Console.error(JSONUtil.toJsonStr(result));
+        }
+        List<Coin> coins = JSONUtil.toList(JSONUtil.parseArray(result.getData()), Coin.class);
+        System.out.println(coins);
+    }
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/UdunException.java b/trading-order-service/src/main/java/com/yami/trading/UD/UdunException.java
new file mode 100644
index 0000000..5aa268e
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/UdunException.java
@@ -0,0 +1,28 @@
+package com.yami.trading.UD;
+
+public class UdunException extends RuntimeException {
+    private Integer code;
+    private String message;
+
+    public UdunException(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/UD/UdunUtils.java b/trading-order-service/src/main/java/com/yami/trading/UD/UdunUtils.java
new file mode 100644
index 0000000..9aee3c6
--- /dev/null
+++ b/trading-order-service/src/main/java/com/yami/trading/UD/UdunUtils.java
@@ -0,0 +1,84 @@
+package com.yami.trading.UD;
+
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.json.JSONUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class UdunUtils {
+    private static Logger logger = LoggerFactory.getLogger(UdunUtils.class);
+
+    public static String post(String gateway, String merchantKey, String path, String body) {
+        try {
+            // 创建 URL 对象
+            URL url = new URL(gateway+path);
+
+            // 打开连接
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+            // 设置请求方法为 POST
+            connection.setRequestMethod("POST");
+
+            // 设置请求头
+            connection.setRequestProperty("Content-Type", "application/json");
+            connection.setRequestProperty("Accept", "application/json");
+
+            // 启用输入输出流
+            connection.setDoOutput(true);
+
+            String rawBody = parseParams(merchantKey, body);
+
+            // 写入请求体
+            try (OutputStream os = connection.getOutputStream()) {
+                byte[] input = rawBody.getBytes("utf-8");
+                os.write(input, 0, input.length);
+            }
+
+            // 获取响应代码
+            int responseCode = connection.getResponseCode();
+
+            // 读取响应
+            try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
+                String inputLine;
+                StringBuilder response = new StringBuilder();
+                while ((inputLine = in.readLine()) != null) {
+                    response.append(inputLine);
+                }
+                return response.toString();
+            }
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static String parseParams(String merchantKey, String body) {
+        Map<String, String> params = new HashMap<>();
+        String timestamp = System.currentTimeMillis() + "";
+        String nonce = RandomUtil.randomString(6);
+        String sign = sign(merchantKey, timestamp, nonce, body);
+        params.put("timestamp", timestamp);
+        params.put("nonce", nonce);
+        params.put("sign", sign);
+        params.put("body", body);
+        return JSONUtil.toJsonStr(params);
+    }
+
+    public static String sign(String key, String timestamp, String nonce, String body) {
+        String raw = body + key + nonce + timestamp;
+        return SecureUtil.md5(raw);
+    }
+
+}
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
index 4829ec0..1aa139e 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
@@ -172,6 +172,7 @@
             map.put("amount", order.getVolume().multiply(order.getUnitAmount()));
             map.put("amount_open", order.getVolumeOpen().multiply(order.getUnitAmount()));
             map.put("fee", order.getFee());
+            map.put("funding_fee", order.getFundingFee());
             map.put("deposit", order.getDeposit());
             data.add(map);
         }
@@ -233,46 +234,60 @@
         log.info("{}  --- order --- {}  --- {}", order.getSymbol(), item.getUuid(), levers.size());
         checkLever(order, levers);
 
-        BigDecimal sourceLeverRate = order.getLeverRate();
-        sourceLeverRate = sourceLeverRate == null ? BigDecimal.ZERO : sourceLeverRate;
+//        BigDecimal sourceLeverRate = order.getLeverRate();
+//        sourceLeverRate = sourceLeverRate == null ? BigDecimal.ZERO : sourceLeverRate;
 
-        List<ContractOrder> contractOrderSubmitted = contractOrderService.findSubmitted(order.getPartyId(),
-                order.getSymbol(), order.getDirection());
-        for (int i = 0; i < contractOrderSubmitted.size(); i++) {
-            BigDecimal targetLeverRate = contractOrderSubmitted.get(i).getLeverRate();
-            targetLeverRate = targetLeverRate == null ? BigDecimal.ZERO : targetLeverRate;
-            if (sourceLeverRate.compareTo(targetLeverRate) != 0) {
-                throw new YamiShopBindException("存在不同杠杆的持仓单");
-            }
-        }
-
-        List<ContractApplyOrder> applyOrderSubmittedList = this.findSubmitted(order.getPartyId(),
-                order.getSymbol(), "open", order.getDirection());
-        for (int i = 0; i < applyOrderSubmittedList.size(); i++) {
-            BigDecimal targetLeverRate = applyOrderSubmittedList.get(i).getLeverRate();
-            targetLeverRate = targetLeverRate == null ? BigDecimal.ZERO : targetLeverRate;
-            if (sourceLeverRate.compareTo(targetLeverRate) != 0) {
-                throw new YamiShopBindException("存在不同杠杆的持仓单");
-            }
-        }
-
+//        List<ContractOrder> contractOrderSubmitted = contractOrderService.findSubmitted(order.getPartyId(),
+//                order.getSymbol(), order.getDirection());
+//        for (int i = 0; i < contractOrderSubmitted.size(); i++) {
+//            BigDecimal targetLeverRate = contractOrderSubmitted.get(i).getLeverRate();
+//            targetLeverRate = targetLeverRate == null ? BigDecimal.ZERO : targetLeverRate;
+//            if (sourceLeverRate.compareTo(targetLeverRate) != 0) {
+//                throw new YamiShopBindException("存在不同杠杆的持仓单");
+//            }
+//        }
+//
+//        List<ContractApplyOrder> applyOrderSubmittedList = this.findSubmitted(order.getPartyId(),
+//                order.getSymbol(), "open", order.getDirection());
+//        for (int i = 0; i < applyOrderSubmittedList.size(); i++) {
+//            BigDecimal targetLeverRate = applyOrderSubmittedList.get(i).getLeverRate();
+//            targetLeverRate = targetLeverRate == null ? BigDecimal.ZERO : targetLeverRate;
+//            if (sourceLeverRate.compareTo(targetLeverRate) != 0) {
+//                throw new YamiShopBindException("存在不同杠杆的持仓单");
+//            }
+//        }
+        //下单数量
         BigDecimal volume = order.getVolume();
+        //当前价格
+        List<Realtime> list = dataService.realtime(order.getSymbol());
+        double close = 0;
+
+        /**
+         * 限价单
+         */
+        if ("limit".equals(order.getOrderPriceType())) {
+            close = order.getPrice().doubleValue();
+        }else{
+            close = list.get(0).getClose();
+        }
+
         if(StringUtils.isEmptyString(order.getOrderNo())) {
             order.setOrderNo(DateUtil.getToday("yyMMddHHmmss") + RandomUtil.getRandomNum(8));
         }
         order.setUnitAmount(BigDecimal.valueOf(item.getUnitAmount()));
 
-        order.setFee(BigDecimal.valueOf(item.getUnitFee()).multiply(order.getVolume()));
-        order.setDeposit(BigDecimal.valueOf(item.getUnitAmount()).multiply(order.getVolume()));
+
+        order.setDeposit(BigDecimal.valueOf(close).multiply(order.getVolume()).divide(order.getLeverRate()));
+        order.setFee(BigDecimal.valueOf(item.getUnitFee()).multiply(order.getDeposit()).divide(order.getLeverRate()));
         BigDecimal fee = order.getFee();
-        if (order.getLeverRate() != null) {
-            // 加上杠杆
-            order.setVolume(order.getVolume().multiply(order.getLeverRate()));
-            Syspara syspara = sysparaService.find("perpetual_contracts");
-            if (ObjectUtils.isEmpty(syspara)||"0".equals(syspara.getSvalue())) {
-//                order.setFee(fee.multiply(order.getLeverRate()));
-            }
-        }
+//        if (order.getLeverRate() != null) {
+//            // 加上杠杆
+//            order.setVolume(order.getVolume().multiply(order.getLeverRate()));
+//            Syspara syspara = sysparaService.find("perpetual_contracts");
+//            if (ObjectUtils.isEmpty(syspara)||"0".equals(syspara.getSvalue())) {
+////                order.setFee(fee.multiply(order.getLeverRate()));
+//            }
+//        }
 
 		Syspara syspara = sysparaService.find("u_standard_contract");
         BigDecimal deposit = order.getDeposit();
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
index fda90c8..43d9b73 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
@@ -24,6 +24,7 @@
 import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDate;
 import java.time.ZoneId;
@@ -53,6 +54,83 @@
     @Resource
     private SysparaService sysparaService;
     private Logger logger = LogManager.getLogger(ContractOrderCalculationServiceImpl.class);
+
+    private BigDecimal defaultZero(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    private BigDecimal estimateAccruedFundingFee(ContractOrder order) {
+        if (order == null || order.getCreateTime() == null) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal borrowedAmount = defaultZero(order.getBorrowedAmount());
+        if (borrowedAmount.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        long holdHours = Duration.between(order.getCreateTime().toInstant(), Instant.now()).toHours();
+        long settlementPeriods = holdHours / 4;
+        if (settlementPeriods <= 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal conservativeRate = new BigDecimal("0.001");
+        return borrowedAmount.multiply(conservativeRate)
+                .multiply(BigDecimal.valueOf(settlementPeriods))
+                .setScale(8, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal calculateType1ForceClosePrice(ContractOrder order, Wallet wallet) {
+        BigDecimal volume = defaultZero(order.getVolume());
+        BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice());
+        if (volume.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        List<ContractOrder> list = contractOrderService.findSubmitted(order.getPartyId(), null, null, null, null, null);
+        BigDecimal otherEquity = BigDecimal.ZERO;
+        for (ContractOrder contractOrder : list) {
+            if (ContractOrder.STATE_SUBMITTED.equals(contractOrder.getState())) {
+                contractOrderService.wrapProfit(contractOrder);
+            }
+            if (order.getUuid().equals(contractOrder.getUuid())) {
+                continue;
+            }
+            otherEquity = otherEquity.add(defaultZero(contractOrder.getProfit()).add(defaultZero(contractOrder.getDeposit())));
+        }
+
+        BigDecimal accruedFundingFee = estimateAccruedFundingFee(order);
+        BigDecimal baseEquity = defaultZero(wallet.getMoney())
+                .add(otherEquity)
+                .add(defaultZero(order.getDeposit()))
+                .subtract(accruedFundingFee);
+        BigDecimal priceOffset = baseEquity.divide(volume, 10, RoundingMode.HALF_UP);
+        if (ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())) {
+            return tradeAvgPrice.subtract(priceOffset);
+        }
+        return tradeAvgPrice.add(priceOffset);
+    }
+
+    private BigDecimal calculateType2ForceClosePrice(ContractOrder order) {
+        BigDecimal volume = defaultZero(order.getVolume());
+        BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice());
+        if (volume.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal thresholdRatio = order_close_line.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP);
+        if (thresholdRatio.compareTo(BigDecimal.ZERO) <= 0) {
+            return tradeAvgPrice;
+        }
+        BigDecimal availableDeposit = defaultZero(order.getDeposit()).subtract(estimateAccruedFundingFee(order));
+        if (availableDeposit.compareTo(BigDecimal.ZERO) <= 0) {
+            return tradeAvgPrice;
+        }
+        BigDecimal requiredLoss = availableDeposit.divide(thresholdRatio, 10, RoundingMode.HALF_UP);
+        BigDecimal priceOffset = requiredLoss.divide(volume, 10, RoundingMode.HALF_UP);
+        if (ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())) {
+            return tradeAvgPrice.subtract(priceOffset);
+        }
+        return tradeAvgPrice.add(priceOffset);
+    }
+
     @Override
     public void saveCalculation(String order_no) {
         try {
@@ -70,6 +148,7 @@
             Realtime realtime = list.get(0);
 
             BigDecimal close = new BigDecimal(realtime.getClose());
+            settle(order, "watch", close);
 
             BigDecimal add = order.getTradeAvgPrice().add(order.getPips());
             BigDecimal subtract = order.getTradeAvgPrice().subtract(order.getPips());
@@ -186,11 +265,10 @@
         /**
          * 根据价格变化百分比和保证金计算盈亏金额
          */
+        BigDecimal priceChangeRatio = currentPrice.subtract(order.getTradeAvgPrice())
+            .divide(order.getTradeAvgPrice(), 6, RoundingMode.DOWN);
 
-            BigDecimal priceChangeRatio = currentPrice.subtract(order.getTradeAvgPrice())
-                .divide(order.getTradeAvgPrice(), 6, RoundingMode.DOWN);
-
-        BigDecimal margin = order.getUnitAmount().multiply(order.getVolumeOpen()); // 这是用户实际的投资金额
+        BigDecimal margin = order.getTradeAvgPrice().multiply(order.getVolume()); // 这是用户当前持仓对应的投资金额
 
         BigDecimal profitAmount = margin.multiply(priceChangeRatio);
 
@@ -256,53 +334,24 @@
         }
         BigDecimal profit1 = contractOrderService.getCacheProfit(order.getUuid()).getProfit();
         if (order_close_line_type == 1) {
-            /**
-             * 收益
-             */
-            BigDecimal profit = BigDecimal.ZERO;
-
             Wallet wallet = this.walletService.findByUserId(order.getPartyId().toString());
-            // 计算所有除自己以外的profit
-            BigDecimal profitExptThis = profit.subtract(profit1).subtract(order.getDeposit());
-            /**
-             * profitAll+wallet<=0
-             * profitAll<=wallet 强平
-             * p1 +E (p2~pn) <=wallet
-             * (currentPrice-tradavg)*pipAmount*volume/pips + depost1 <=wallet-E(p2~pn)
-             */
-            BigDecimal left = wallet.getMoney().negate().subtract(profitExptThis).subtract(order.getDeposit());
-            BigDecimal pipsAmount = order.getPipsAmount();
-            if(pipsAmount.doubleValue() <= 0.00){
-                pipsAmount = new BigDecimal("0.01");
-            }
-            BigDecimal overLine = (left.multiply(pips).divide(pipsAmount, 10, RoundingMode.HALF_UP)
-                    .divide(order.getVolume(), 10, RoundingMode.HALF_UP));
             Integer decimal = itemService.getDecimal(order.getSymbol());
-            BigDecimal forceClose = BigDecimal.ZERO;
-            // 买多,从买价跌多少
-            if (order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)) {
-                forceClose = order.getTradeAvgPrice().add(overLine).setScale(decimal, RoundingMode.HALF_UP);
-                //买跌,涨到多少
-            } else {
-                forceClose = order.getTradeAvgPrice().subtract(overLine).setScale(decimal, RoundingMode.HALF_UP);
-            }
+            BigDecimal forceClose = calculateType1ForceClosePrice(order, wallet).setScale(decimal, RoundingMode.HALF_UP);
             if (forceClose.compareTo(BigDecimal.ZERO) < 0) {
                 forceClose = BigDecimal.ZERO;
             }
             order.setForceClosePrice(forceClose.toPlainString());
             this.contractOrderService.updateByIdBuffer(order);
             List<ContractOrder> list = contractOrderService.findSubmitted(order.getPartyId(), null, null, null, null, null);
+            BigDecimal totalEquity = defaultZero(wallet.getMoney());
             for(ContractOrder contractOrder :list) {
             	if(ContractOrder.STATE_SUBMITTED.equals(contractOrder.getState())){
             		contractOrderService.wrapProfit(contractOrder);
             	}
+                totalEquity = totalEquity.add(defaultZero(contractOrder.getProfit()).add(defaultZero(contractOrder.getDeposit())));
             }
-			for (int i = 0; i < list.size(); i++) {
-				ContractOrder close_line = list.get(i);
-				profit = profit.add(close_line.getProfit().add(close_line.getDeposit()));
-			}
 
-            if (profit.add(wallet.getMoney()).compareTo(BigDecimal.ZERO) <= 0) {
+            if (totalEquity.compareTo(BigDecimal.ZERO) <= 0) {
                 /**
                  * 触发全仓强平
                  */
@@ -310,6 +359,13 @@
 
             }
         } else {
+            Integer decimal = itemService.getDecimal(order.getSymbol());
+            BigDecimal forceClose = calculateType2ForceClosePrice(order).setScale(decimal, RoundingMode.HALF_UP);
+            if (forceClose.compareTo(BigDecimal.ZERO) < 0) {
+                forceClose = BigDecimal.ZERO;
+            }
+            order.setForceClosePrice(forceClose.toPlainString());
+            this.contractOrderService.updateByIdBuffer(order);
             BigDecimal divide = order.getDeposit().divide(profit1.abs(), 10, RoundingMode.HALF_UP);
             if (profit1.compareTo(BigDecimal.ZERO) < 0 && divide.compareTo(order_close_line.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP)) <= 0) {
                 /**
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
index f29d4a5..4ccdca1 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
@@ -63,6 +63,7 @@
 import java.math.RoundingMode;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -73,6 +74,7 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -377,7 +379,10 @@
          * 收益
          */
         BigDecimal volume = order.getVolume();
-        BigDecimal profit = settle(order, order.getVolume());
+        BigDecimal fundingFee = this.calculateFundingFee(order, volume, new Date());
+        BigDecimal profit = settle(order, order.getVolume()).subtract(fundingFee);
+        order.setAmountClose(order.getAmountClose().subtract(fundingFee));
+        order.setFundingFee(defaultZero(order.getFundingFee()).add(fundingFee));
         String symbol = order.getSymbol();
 //        Item item = itemService.findBySymbol(symbol);
 //        profit = exchangeRateService.getUsdtByType(profit, item.getType());
@@ -406,11 +411,6 @@
             walletService.updateMoney(order.getSymbol(), partyId, profit, BigDecimal.ZERO,
                     Constants.MONEYLOG_CATEGORY_CONTRACT, Constants.WALLET_USDT, Constants.MONEYLOG_CONTENT_CONTRACT_CLOSE, "平仓,平仓合约数[" + volume + "],订单号[" + order.getOrderNo() + "]");
         }
-        order.setState(ContractOrder.STATE_CREATED);
-        order.setVolume(BigDecimal.ZERO);
-        order.setDeposit(BigDecimal.ZERO);
-        order.setCloseTime(DateUtil.currentSeconds());
-        order.setCloseTimeTs(DateUtil.currentSeconds());
 //        List<Realtime> list = this.dataService.realtime(order.getSymbol());
 //        // 平仓时候把当前价格先更新回去
 //        if (list.size() != 0) {
@@ -466,6 +466,7 @@
             if (cacheProfit != null) {
                 contractOrder.setProfit(cacheProfit.getProfit());
                 contractOrder.setCloseAvgPrice(cacheProfit.getCloseAvgPrice());
+                contractOrder.setForceClosePrice(cacheProfit.getForceClosePrice());
             } else {
                 contractOrder.setProfit(BigDecimal.ZERO);
 
@@ -630,11 +631,6 @@
      * @param volume 平仓的张数
      */
     public BigDecimal settle(ContractOrder order, BigDecimal volume) {
-        /**
-         * 平仓比率
-         */
-//        BigDecimal rate = volume.divide(order.getVolumeOpen(), 10, RoundingMode.HALF_UP);
-
         ContractOrderProfit cacheProfit = getCacheProfit(order.getUuid());
         BigDecimal originProfit = BigDecimal.ZERO;
         if (cacheProfit != null) {
@@ -642,7 +638,16 @@
             order.setCloseAvgPrice(cacheProfit.getCloseAvgPrice());
         }
 
-        BigDecimal profit = order.getDeposit().add(originProfit);
+        BigDecimal currentVolume = defaultZero(order.getVolume());
+        if (currentVolume.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal closeRatio = volume.divide(currentVolume, 10, RoundingMode.HALF_UP);
+        BigDecimal currentDeposit = defaultZero(order.getDeposit());
+        BigDecimal currentBorrowed = getCurrentBorrowedAmount(order);
+        BigDecimal releasedDeposit = currentDeposit.multiply(closeRatio).setScale(8, RoundingMode.HALF_UP);
+        BigDecimal realizedProfit = originProfit.multiply(closeRatio).setScale(8, RoundingMode.HALF_UP);
+        BigDecimal profit = releasedDeposit.add(realizedProfit);
 
         if (ContractOrder.ORDER_FOLLOW == order.getFollow()) { // 跟单还得减去利息收益
             BigDecimal orderAmount = order.getUnitAmount().multiply(order.getTradeAvgPrice()).multiply(order.getLeverRate()); //订单总金额
@@ -669,87 +674,203 @@
         }
 
         order.setAmountClose(order.getAmountClose().add(profit));
-        order.setVolume(order.getVolume().subtract(volume));
-        order.setDeposit(order.getDeposit().subtract(order.getDepositOpen()));
-        if (order.getVolume().compareTo(BigDecimal.ZERO) <= 0) {
+        BigDecimal remainVolume = currentVolume.subtract(volume);
+        BigDecimal remainDeposit = currentDeposit.subtract(releasedDeposit).max(BigDecimal.ZERO);
+        BigDecimal remainBorrowed = currentBorrowed.subtract(currentBorrowed.multiply(closeRatio).setScale(8, RoundingMode.HALF_UP)).max(BigDecimal.ZERO);
+        BigDecimal remainProfit = originProfit.subtract(realizedProfit).setScale(8, RoundingMode.HALF_UP);
+        order.setVolume(remainVolume.max(BigDecimal.ZERO));
+        if (remainVolume.compareTo(BigDecimal.ZERO) > 0) {
+            order.setVolumeOpen(remainVolume);
+            order.setDeposit(remainDeposit);
+            order.setDepositOpen(remainDeposit);
+            order.setBorrowedAmount(remainBorrowed);
+            order.setProfit(remainProfit);
+        } else {
             order.setState(ContractOrder.STATE_CREATED);
             order.setCloseTime(DateUtil.currentSeconds());
             order.setCloseTimeTs(DateUtil.currentSeconds());
+            order.setDeposit(BigDecimal.ZERO);
+            order.setBorrowedAmount(BigDecimal.ZERO);
+            order.setProfit(originProfit);
         }
-        order.setProfit(originProfit);
         return profit;
+    }
+
+    private BigDecimal calculateFundingFee(ContractOrder order, BigDecimal closeVolume, Date closeTime) {
+        if (order == null || closeVolume == null || closeTime == null) {
+            return BigDecimal.ZERO;
+        }
+        if (closeVolume.compareTo(BigDecimal.ZERO) <= 0
+                || order.getVolumeOpen() == null
+                || order.getVolumeOpen().compareTo(BigDecimal.ZERO) <= 0
+                || order.getCreateTime() == null) {
+            return BigDecimal.ZERO;
+        }
+
+        long holdHours = Duration.between(order.getCreateTime().toInstant(), closeTime.toInstant()).toHours();
+        long settlementPeriods = holdHours / 4;
+        if (settlementPeriods <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        BigDecimal fundingRateTotal = BigDecimal.ZERO;
+        for (int i = 0; i < settlementPeriods; i++) {
+            double periodRate = ThreadLocalRandom.current().nextDouble(-0.001D, 0.0010000001D);
+            fundingRateTotal = fundingRateTotal.add(BigDecimal.valueOf(periodRate));
+        }
+
+        BigDecimal currentVolume = defaultZero(order.getVolume());
+        if (currentVolume.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+
+        BigDecimal closeRatio = closeVolume.divide(currentVolume, 10, RoundingMode.HALF_UP);
+        BigDecimal borrowedBase = getCurrentBorrowedAmount(order).multiply(closeRatio);
+        return borrowedBase.multiply(fundingRateTotal).setScale(8, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal defaultZero(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    private BigDecimal calculateBorrowedAmount(BigDecimal positionBase, BigDecimal leverRate) {
+        BigDecimal safeBase = defaultZero(positionBase);
+        BigDecimal safeLeverRate = defaultZero(leverRate);
+        if (safeBase.compareTo(BigDecimal.ZERO) <= 0 || safeLeverRate.compareTo(BigDecimal.ONE) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        return safeBase.multiply(safeLeverRate.subtract(BigDecimal.ONE))
+                .divide(safeLeverRate, 10, RoundingMode.HALF_UP);
+    }
+
+    private BigDecimal getCurrentBorrowedAmount(ContractOrder order) {
+        if (order == null) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal borrowedAmount = defaultZero(order.getBorrowedAmount());
+        if (borrowedAmount.compareTo(BigDecimal.ZERO) > 0) {
+            return borrowedAmount;
+        }
+        return calculateBorrowedAmount(order.getDeposit(), order.getLeverRate());
+    }
+
+    private boolean shouldMergeCryptoPosition(Item item) {
+        return item != null && Item.cryptos.equalsIgnoreCase(item.getType());
+    }
+
+    private void mergeOpenPosition(ContractOrder order, ContractApplyOrder applyOrder, BigDecimal tradePrice) {
+        BigDecimal oldVolume = defaultZero(order.getVolume());
+        BigDecimal newVolume = defaultZero(applyOrder.getVolume());
+        BigDecimal totalVolume = oldVolume.add(newVolume);
+        if (totalVolume.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+
+        BigDecimal weightedTradeAmount = defaultZero(order.getTradeAvgPrice()).multiply(oldVolume)
+                .add(defaultZero(tradePrice).multiply(newVolume));
+        BigDecimal avgTradePrice = weightedTradeAmount.divide(totalVolume, 10, RoundingMode.HALF_UP);
+
+        order.setTradeAvgPrice(avgTradePrice);
+        order.setVolume(totalVolume);
+        order.setVolumeOpen(totalVolume);
+        order.setDeposit(defaultZero(order.getDeposit()).add(defaultZero(applyOrder.getDeposit())));
+        order.setDepositOpen(defaultZero(order.getDepositOpen()).add(defaultZero(applyOrder.getDeposit())));
+        order.setFee(defaultZero(order.getFee()).add(defaultZero(applyOrder.getFee())));
+        order.setBorrowedAmount(getCurrentBorrowedAmount(order)
+                .add(calculateBorrowedAmount(applyOrder.getDeposit(), applyOrder.getLeverRate())));
+        order.setLeverRate(applyOrder.getLeverRate());
+        order.setOrderPriceType(applyOrder.getOrderPriceType());
+        if (applyOrder.getStopPriceProfit() != null && applyOrder.getStopPriceProfit().compareTo(BigDecimal.ZERO) > 0) {
+            order.setStopPriceProfit(applyOrder.getStopPriceProfit());
+        }
+        if (applyOrder.getStopPriceLoss() != null && applyOrder.getStopPriceLoss().compareTo(BigDecimal.ZERO) > 0) {
+            order.setStopPriceLoss(applyOrder.getStopPriceLoss());
+        }
     }
 
     @Transactional
     public void saveOpen(ContractApplyOrder applyOrder, Realtime realtime) {
         Item item = this.itemService.findBySymbol(applyOrder.getSymbol());
+        BigDecimal tradePrice = BigDecimal.valueOf(realtime.getClose());
+        ContractOrder order;
+        List<ContractOrder> submittedOrders = shouldMergeCryptoPosition(item)
+                ? this.findSubmitted(applyOrder.getPartyId(), applyOrder.getSymbol(), applyOrder.getDirection())
+                : new ArrayList<>();
+        if (CollectionUtil.isNotEmpty(submittedOrders)) {
+            order = submittedOrders.get(0);
+            mergeOpenPosition(order, applyOrder, tradePrice);
+            update(order);
+        } else {
+            order = new ContractOrder();
+            order.setPartyId(applyOrder.getPartyId());
+            order.setSymbol(applyOrder.getSymbol());
+            String orderNo = com.yami.trading.common.util.DateUtil.formatDate(new Date(), "yyMMddHHmmss") + RandomUtil.getRandomNum(8);
+            order.setOrderNo(orderNo);
+            order.setDirection(applyOrder.getDirection());
+            order.setLeverRate(applyOrder.getLeverRate());
+            order.setVolume(applyOrder.getVolume());
+            order.setVolumeOpen(applyOrder.getVolumeOpen());
+            order.setOrderPriceType(applyOrder.getOrderPriceType());
+            order.setUnitAmount(applyOrder.getUnitAmount());
+            order.setFee(applyOrder.getFee());
+            order.setFundingFee(BigDecimal.ZERO);
+            order.setBorrowedAmount(calculateBorrowedAmount(applyOrder.getDeposit(), applyOrder.getLeverRate()));
+            order.setDeposit(applyOrder.getDeposit());
+            order.setDepositOpen(applyOrder.getDeposit());
 
-        ContractOrder order = new ContractOrder();
-        order.setPartyId(applyOrder.getPartyId());
-        order.setSymbol(applyOrder.getSymbol());
-        String orderNo = com.yami.trading.common.util.DateUtil.formatDate(new Date(), "yyMMddHHmmss") + RandomUtil.getRandomNum(8);
-        order.setOrderNo(orderNo);
-        order.setDirection(applyOrder.getDirection());
-        order.setLeverRate(applyOrder.getLeverRate());
-        order.setVolume(applyOrder.getVolume());
-        order.setVolumeOpen(applyOrder.getVolumeOpen());
-        order.setOrderPriceType(applyOrder.getOrderPriceType());
-        order.setUnitAmount(applyOrder.getUnitAmount());
-        order.setFee(applyOrder.getFee());
-        order.setDeposit(applyOrder.getDeposit());
-        order.setDepositOpen(applyOrder.getDeposit());
+            order.setTradeAvgPrice(tradePrice);
+            order.setStopPriceProfit(applyOrder.getStopPriceProfit());
+            order.setStopPriceLoss(applyOrder.getStopPriceLoss());
 
-        order.setTradeAvgPrice(BigDecimal.valueOf(realtime.getClose()));
-        order.setStopPriceProfit(applyOrder.getStopPriceProfit());
-        order.setStopPriceLoss(applyOrder.getStopPriceLoss());
+            order.setPips(BigDecimal.valueOf(item.getPips()));
+            order.setPipsAmount(BigDecimal.valueOf(item.getPipsAmount()));
+            order.setFollow(applyOrder.getFollow());
+            save(order);
+            RedisUtil.set(ContractRedisKeys.CONTRACT_ORDERNO + order.getOrderNo(), order);
 
-        order.setPips(BigDecimal.valueOf(item.getPips()));
-        order.setPipsAmount(BigDecimal.valueOf(item.getPipsAmount()));
-        order.setFollow(applyOrder.getFollow());
-        // 爆仓是爆整个钱包
-//        BigDecimal forceClose = BigDecimal.ZERO;
-//        BigDecimal base = order.getDepositOpen().multiply(order.getPips()).divide(order.getPipsAmount(), 10, RoundingMode.HALF_UP).divide(order.getVolume(),10, RoundingMode.HALF_UP);
-//        if(order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)){
-//            forceClose = order.getTradeAvgPrice().subtract(base).setScale(item.getDecimals(), RoundingMode.HALF_UP);
-//        }else if(order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_SELL)) {
-//            forceClose = order.getTradeAvgPrice().add(base).setScale(item.getDecimals(), RoundingMode.HALF_UP);
-//        }
-//        if(forceClose.compareTo(BigDecimal.ZERO) <0 ){
-//            forceClose  =  BigDecimal.ZERO;
-//        }
-//        order.setForceClosePrice(forceClose.toPlainString());
-        save(order);
-        RedisUtil.set(ContractRedisKeys.CONTRACT_ORDERNO + order.getOrderNo(), order);
+            Map<String, ContractOrder> map = RedisUtil
+                    .get(ContractRedisKeys.CONTRACT_SUBMITTED_ORDER_PARTY_ID + order.getPartyId());
+            if (map == null) {
+                map = new ConcurrentHashMap<String, ContractOrder>();
+            }
+            map.put(order.getOrderNo(), order);
+            RedisUtil.set(ContractRedisKeys.CONTRACT_SUBMITTED_ORDER_PARTY_ID + order.getPartyId(), map);
 
-        Map<String, ContractOrder> map = RedisUtil
-                .get(ContractRedisKeys.CONTRACT_SUBMITTED_ORDER_PARTY_ID + order.getPartyId());
-        if (map == null) {
-            map = new ConcurrentHashMap<String, ContractOrder>();
+            // 获取单个订单的合约总资产、总保证金、总未实现盈利
+            Map<String, BigDecimal> contractAssetsOrder = this.walletService.getMoneyContractByOrder(order);
+
+            BigDecimal contractAssets = RedisUtil.get(ContractRedisKeys.CONTRACT_ASSETS_PARTY_ID + order.getPartyId());
+            if (contractAssets == null) {
+                contractAssets = BigDecimal.ZERO;
+            }
+            BigDecimal contractAssetsDeposit = RedisUtil.get(ContractRedisKeys.CONTRACT_ASSETS_DEPOSIT_PARTY_ID + order.getPartyId());
+            if (contractAssetsDeposit == null) {
+                contractAssetsDeposit = BigDecimal.ZERO;
+            }
+            BigDecimal contractAssetsProfit = RedisUtil.get(ContractRedisKeys.CONTRACT_ASSETS_PROFIT_PARTY_ID + order.getPartyId());
+            if (contractAssetsProfit == null) {
+                contractAssetsProfit = BigDecimal.ZERO;
+            }
+            RedisUtil.set(ContractRedisKeys.CONTRACT_ASSETS_PARTY_ID + order.getPartyId(),
+                    contractAssets.add(contractAssetsOrder.get("money_contract")));
+            RedisUtil.set(ContractRedisKeys.CONTRACT_ASSETS_DEPOSIT_PARTY_ID + order.getPartyId(),
+                    contractAssetsDeposit.add(contractAssetsOrder.get("money_contract_deposit")));
+            RedisUtil.set(ContractRedisKeys.CONTRACT_ASSETS_PROFIT_PARTY_ID + order.getPartyId(),
+                    contractAssetsProfit.add(contractAssetsOrder.get("money_contract_profit")));
         }
-        map.put(order.getOrderNo(), order);
-        RedisUtil.set(ContractRedisKeys.CONTRACT_SUBMITTED_ORDER_PARTY_ID + order.getPartyId(), map);
 
-        // 获取单个订单的合约总资产、总保证金、总未实现盈利
-        Map<String, BigDecimal> contractAssetsOrder = this.walletService.getMoneyContractByOrder(order);
-
-        BigDecimal contractAssets = RedisUtil.get(ContractRedisKeys.CONTRACT_ASSETS_PARTY_ID + order.getPartyId());
-        if (contractAssets == null) {
-            contractAssets = BigDecimal.ZERO;
-        }
-        BigDecimal contractAssetsDeposit = RedisUtil.get(ContractRedisKeys.CONTRACT_ASSETS_DEPOSIT_PARTY_ID + order.getPartyId());
-        if (contractAssetsDeposit == null) {
-            contractAssetsDeposit = BigDecimal.ZERO;
-        }
-        BigDecimal contractAssetsProfit = RedisUtil.get(ContractRedisKeys.CONTRACT_ASSETS_PROFIT_PARTY_ID + order.getPartyId());
-        if (contractAssetsProfit == null) {
-            contractAssetsProfit = BigDecimal.ZERO;
-        }
-        RedisUtil.set(ContractRedisKeys.CONTRACT_ASSETS_PARTY_ID + order.getPartyId(),
-                contractAssets.add(contractAssetsOrder.get("money_contract")));
-        RedisUtil.set(ContractRedisKeys.CONTRACT_ASSETS_DEPOSIT_PARTY_ID + order.getPartyId(),
-                contractAssetsDeposit.add(contractAssetsOrder.get("money_contract_deposit")));
-        RedisUtil.set(ContractRedisKeys.CONTRACT_ASSETS_PROFIT_PARTY_ID + order.getPartyId(),
-                contractAssetsProfit.add(contractAssetsOrder.get("money_contract_profit")));
+        ContractOrder traderOpenOrder = new ContractOrder();
+        traderOpenOrder.setPartyId(order.getPartyId());
+        traderOpenOrder.setOrderNo(order.getOrderNo());
+        traderOpenOrder.setSymbol(order.getSymbol());
+        traderOpenOrder.setDirection(order.getDirection());
+        traderOpenOrder.setLeverRate(applyOrder.getLeverRate());
+        traderOpenOrder.setVolume(applyOrder.getVolume());
+        traderOpenOrder.setVolumeOpen(applyOrder.getVolumeOpen());
+        traderOpenOrder.setUnitAmount(applyOrder.getUnitAmount());
+        traderOpenOrder.setTradeAvgPrice(tradePrice);
+        traderOpenOrder.setStopPriceProfit(applyOrder.getStopPriceProfit());
+        traderOpenOrder.setStopPriceLoss(applyOrder.getStopPriceLoss());
 
         /**
          * 进入市场
@@ -769,7 +890,7 @@
          */
         Trader trader = traderService.findByPartyIdAndChecked(applyOrder.getPartyId(), 1); // 交易员存在
         if (trader != null) {
-            traderFollowUserOrderService.traderOpen(order, contractApplyOrderService, this, 1); // 交易员跟随者开启永续合约委托, 加个跟单标识
+            traderFollowUserOrderService.traderOpen(traderOpenOrder, contractApplyOrderService, this, 1); // 交易员跟随者开启永续合约委托, 加个跟单标识
         }
 
         /**
@@ -820,7 +941,11 @@
         /**
          * 平仓退回的金额
          */
+        BigDecimal fundingFee = this.calculateFundingFee(order, volume, new Date());
         BigDecimal profit = this.settle(order, volume);
+        BigDecimal netProfit = profit.subtract(fundingFee);
+        order.setAmountClose(order.getAmountClose().subtract(fundingFee));
+        order.setFundingFee(defaultZero(order.getFundingFee()).add(fundingFee));
         update(order);
         Wallet wallet = this.walletService.findByUserId(order.getPartyId());
         BigDecimal amount_before = wallet.getMoney();
@@ -828,14 +953,15 @@
         String symbol = order.getSymbol();
 //        Item item = itemService.findBySymbol(symbol);
 //        profit = exchangeRateService.getUsdtByType(profit, item.getType());
-        if (wallet.getMoney().add(profit).compareTo(BigDecimal.ZERO) < 0) {
-            profit = wallet.getMoney().negate();
+        if (wallet.getMoney().add(netProfit).compareTo(BigDecimal.ZERO) < 0) {
+            netProfit = wallet.getMoney().negate();
         }
-        walletService.updateMoney(symbol, order.getPartyId(), profit, BigDecimal.ZERO,
+        walletService.updateMoney(symbol, order.getPartyId(), netProfit, BigDecimal.ZERO,
                 Constants.MONEYLOG_CATEGORY_CONTRACT, Constants.WALLET_USDT, Constants.MONEYLOG_CONTENT_CONTRACT_CLOSE, "平仓,平仓合约数[" + volume + "],订单号[" + order.getOrderNo() + "]");
 
 
         applyOrder.setVolume(applyOrder.getVolume().subtract(volume));
+        applyOrder.setFundingFee(defaultZero(applyOrder.getFundingFee()).add(fundingFee));
         if (applyOrder.getVolume().compareTo(BigDecimal.ZERO) <= 0) {
             applyOrder.setState(ContractApplyOrder.STATE_CREATED);
         }
@@ -921,9 +1047,10 @@
             map.put("stop_price_loss", order.getStopPriceLoss());
         }
         map.put("state", order.getState());
-        map.put("amount", order.getVolume().multiply(order.getUnitAmount()));
-        map.put("amount_open", order.getVolumeOpen().multiply(order.getUnitAmount()));
+        map.put("amount", order.getDeposit());
+        map.put("amount_open", order.getDeposit());
         map.put("fee", order.getFee());
+        map.put("funding_fee", order.getFundingFee());
         map.put("deposit", order.getDeposit());
         map.put("deposit_open", order.getDepositOpen());
         map.put("change_ratio", order.getChangeRatio());
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/impl/FollowWalletServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/impl/FollowWalletServiceImpl.java
index c346e42..4a68115 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/impl/FollowWalletServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/impl/FollowWalletServiceImpl.java
@@ -256,16 +256,7 @@
                     }
 
                 }
-                // 真正下单里
-                double order_volume = 1;
-
-                if (order.getLeverRate() != null && order.getLeverRate().compareTo(BigDecimal.ZERO) != 0) {
-                    order_volume = order.getVolumeOpen().divide(order.getLeverRate(), 6, RoundingMode.FLOOR).doubleValue();
-                } else {
-                    order_volume = order.getVolumeOpen().doubleValue();
-                }
-
-                double amount = Arith.add(Arith.mul(order_volume, order.getUnitAmount().doubleValue()), order.getProfit().doubleValue());
+                double amount = order.getDeposit().add(order.getProfit()).doubleValue();
                 money_contract = Arith.add(amount, money_contract);
                 money_contract_deposit = Arith.add(order.getDeposit().doubleValue(), money_contract_deposit);
                 money_contract_profit = Arith.add(order.getProfit().doubleValue(), money_contract_profit);
@@ -780,14 +771,7 @@
             return moneysContract;
         }
         ApplicationUtil.getBean(ContractOrderService.class).wrapProfit(order);
-        BigDecimal orderVolume = BigDecimal.ONE;
-
-        if (order.getLeverRate() != null && order.getLeverRate().compareTo(BigDecimal.ZERO) != 0) {
-            orderVolume = order.getVolumeOpen().divide(order.getLeverRate(), 2, RoundingMode.FLOOR);
-        } else {
-            orderVolume = order.getVolumeOpen();
-        }
-        BigDecimal moneyContract = orderVolume.multiply(order.getUnitAmount()).add(order.getProfit());
+        BigDecimal moneyContract = order.getDeposit().add(order.getProfit());
         BigDecimal moneyContractDeposit = order.getDeposit();
         BigDecimal moneyContractProfit = order.getProfit();
 
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
index ef7de6a..ee38008 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/impl/RechargeBlockchainOrderServiceImpl.java
@@ -89,7 +89,10 @@
 //        Date now = new Date();
         RechargeBlockchainOrder recharge = getById(id);
         if (recharge == null) {
-            throw new YamiShopBindException("参数错误!");
+            recharge = findByOrderNo(id);
+            if (recharge == null) {
+                throw new YamiShopBindException("参数错误!");
+            }
         }
         User party = userService.getById(recharge.getPartyId());
         if (party == null) {
@@ -119,8 +122,25 @@
          * 如果是usdt则加入wallet,否则寻找walletExtend里相同币种
          */
         Syspara user_recom_bonus_open = sysparaService.find("user_recom_bonus_open");
-        if ("usdt".equals(recharge.getSymbol())) {
+        if ("usdt".equals(recharge.getSymbol()) || "usdc".equals(recharge.getSymbol())) {
             double amount1 = recharge.getVolume();
+            if ("usdc".equals(recharge.getSymbol())) {
+                List<Realtime> realtime_list = this.dataService.realtime(recharge.getSymbol());
+                log.info("充值usdc转为usdt::" + realtime_list);
+                Realtime realtime = null;
+                if (realtime_list.size() > 0) {
+                    realtime = realtime_list.get(0);
+                } else {
+                    throw new YamiShopBindException("系统错误,请稍后重试");
+                }
+                // 对应usdt价格
+                double transfer_usdt = realtime.getClose();
+                double volume = recharge.getVolume();
+
+                // 币种usdt价格= 币种价格×充值数量
+                amount1 = Arith.mul(recharge.getVolume(), transfer_usdt);
+                log.info("充值usdc转为usdt::" + amount1);
+            }
             Wallet wallet = new Wallet();
             wallet = walletService.saveWalletByPartyId(recharge.getPartyId());
             double amount_before = wallet.getMoney().doubleValue();
@@ -268,7 +288,7 @@
                 double baseAmount = Double.parseDouble(recharges[1]);
                 // 用户已完成USDT订单
                 long number = moneyLogService.getMoneyLogByFirstRecharge(recharge.getPartyId()) == null ? 0 : 1;
-                        //this.findByPartyIdAndLargerVolume(recharge.getPartyId(), 1,baseAmount);
+                //this.findByPartyIdAndLargerVolume(recharge.getPartyId(), 1,baseAmount);
                 rechargeBonusService.saveFirstUsdtBounsHandle(recharge,transfer_usdt,number,recharges);
             }
             /**
@@ -426,7 +446,7 @@
         if ("".equals(recharge.getOrderNo()) || recharge.getOrderNo() == null) {
             recharge.setOrderNo(DateUtil.getToday("yyMMddHHmmss") + RandomUtil.getRandomNum(8));
         }
-        save(recharge);
+        saveOrUpdate(recharge);
         // 保存资金日志
         WalletLog walletLog = new WalletLog();
         walletLog.setCategory(Constants.MONEYLOG_CATEGORY_RECHARGE);
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java
index 35a782f..fbadbe1 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/impl/UserServiceImpl.java
@@ -1011,6 +1011,7 @@
 //		if (reg.getUsername().indexOf("@") == -1) {
         if (type.equals("1")) {
             // 手机注册
+            rejectMainlandChinaPhoneRegister(username);
 //			if (StringUtils.isEmptyString(reg.getUsername()) || !Strings.isNumber(reg.getUsername()) || reg.getUsername().length() > 15) {
             if (StringUtils.isEmptyString(username) || username.length() > 20) {
                 throw new YamiShopBindException("请输入正确的手机号码");
@@ -1617,6 +1618,7 @@
         User user = null;
         // 手机
         if (type == 1) {
+            rejectMainlandChinaPhoneRegister(userName);
             if (!isValidPhone(userName)) {
                 throw new YamiShopBindException("手机号格式不正常");
             }
@@ -1778,6 +1780,22 @@
         return user;
     }
 
+    /**
+     * 禁止大陆 +86 / 86 前缀手机号注册(与风控一致)
+     */
+    private void rejectMainlandChinaPhoneRegister(String phoneRaw) {
+        if (StringUtils.isEmptyString(phoneRaw)) {
+            return;
+        }
+        String phone = phoneRaw.trim();
+        if (phone.startsWith("+86")) {
+            throw new YamiShopBindException("不支持+86大陆手机号注册");
+        }
+        if (phone.matches("^86(1[3-9])\\d{9}$")) {
+            throw new YamiShopBindException("不支持86前缀大陆手机号注册");
+        }
+    }
+
     // 手机号校验
     private boolean isValidPhone(String username) {
         Pattern p = Pattern.compile("[0-9]*");
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/impl/WalletServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/impl/WalletServiceImpl.java
index 3f1a09c..5446ee6 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/impl/WalletServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/impl/WalletServiceImpl.java
@@ -262,16 +262,7 @@
                     }
 
                 }
-                // 真正下单里
-                double order_volume = 1;
-
-                if (order.getLeverRate() != null && order.getLeverRate().compareTo(BigDecimal.ZERO) != 0) {
-                    order_volume = order.getVolumeOpen().divide(order.getLeverRate(), 6, RoundingMode.FLOOR).doubleValue();
-                } else {
-                    order_volume = order.getVolumeOpen().doubleValue();
-                }
-
-                double amount = Arith.add(Arith.mul(order_volume, order.getUnitAmount().doubleValue()), order.getProfit().doubleValue());
+                double amount = order.getDeposit().add(order.getProfit()).doubleValue();
                 money_contract = Arith.add(amount, money_contract);
                 money_contract_deposit = Arith.add(order.getDeposit().doubleValue(), money_contract_deposit);
                 money_contract_profit = Arith.add(order.getProfit().doubleValue(), money_contract_profit);
@@ -814,14 +805,7 @@
             return moneysContract;
         }
         ApplicationUtil.getBean(ContractOrderService.class).wrapProfit(order);
-        BigDecimal orderVolume = BigDecimal.ONE;
-
-        if (order.getLeverRate() != null && order.getLeverRate().compareTo(BigDecimal.ZERO) != 0) {
-            orderVolume = order.getVolumeOpen().divide(order.getLeverRate(), 2, RoundingMode.FLOOR);
-        } else {
-            orderVolume = order.getVolumeOpen();
-        }
-        BigDecimal moneyContract = orderVolume.multiply(order.getUnitAmount()).add(order.getProfit());
+        BigDecimal moneyContract = order.getDeposit().add(order.getProfit());
         BigDecimal moneyContractDeposit = order.getDeposit();
         BigDecimal moneyContractProfit = order.getProfit();
 
diff --git a/trading-order-service/src/main/resources/mapper/contract/ContractApplyOrderMapper.xml b/trading-order-service/src/main/resources/mapper/contract/ContractApplyOrderMapper.xml
index bcb3fd1..6f10154 100644
--- a/trading-order-service/src/main/resources/mapper/contract/ContractApplyOrderMapper.xml
+++ b/trading-order-service/src/main/resources/mapper/contract/ContractApplyOrderMapper.xml
@@ -19,6 +19,7 @@
 		a.state AS "state",
 		a.unit_amount AS "unitAmount",
 		a.fee AS "fee",
+		a.funding_fee AS "fundingFee",
 		a.deposit AS "deposit",
 		a.create_by AS "createBy",
 		a.create_time AS "createTime",
diff --git a/trading-order-service/src/main/resources/mapper/contract/ContractOrderMapper.xml b/trading-order-service/src/main/resources/mapper/contract/ContractOrderMapper.xml
index a3041db..e482124 100644
--- a/trading-order-service/src/main/resources/mapper/contract/ContractOrderMapper.xml
+++ b/trading-order-service/src/main/resources/mapper/contract/ContractOrderMapper.xml
@@ -11,6 +11,7 @@
         a.unit_amount AS "unitAmount",
         a.amount_close AS "amountClose",
         a.fee AS "fee",
+        a.funding_fee AS "fundingFee",
         a.deposit AS "deposit",
         a.deposit_open AS "depositOpen",
         a.profit AS "profit",

--
Gitblit v1.9.3