diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..cabc17c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{yml,yaml}] +indent_size = 2 + +[*.{json,xml}] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[*.gradle] +indent_size = 4 + +[Dockerfile] +indent_size = 4 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e735967 --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +# Database +DB_URL=jdbc:mysql://127.0.0.1:3306/wallet_db?allowMultiQueries=true&useSSL=false&characterEncoding=UTF-8&autoReconnect=true +DB_USERNAME=root +DB_PASSWORD=your_secure_password + +# RabbitMQ +RABBITMQ_HOST=127.0.0.1 +RABBITMQ_PORT=5672 +RABBITMQ_USERNAME=guest +RABBITMQ_PASSWORD=guest + +# XXL-Job +XXL_JOB_ADMIN_ADDRESSES=http://127.0.0.1:8099/xxl-job-admin +XXL_JOB_PORT=9999 +XXL_JOB_ACCESS_TOKEN=your_access_token + +# HSM Keystore +KEYSTORE_DIR=/data/keystores +KEYSTORE_PASSWORD=your_keystore_password + +# Encryption +WALLET_CRYPTO_PUSH_KEY=your_32_char_encryption_key_here + +# Logging +LOG_LEVEL=INFO diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1ba381c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,75 @@ +name: CI + +on: + push: + branches: [ master, develop ] + pull_request: + branches: [ master ] + +permissions: + contents: read + +jobs: + build: + name: Build & Test + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + cache-read-only: ${{ github.ref != 'refs/heads/master' }} + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build + run: ./gradlew build -x test --no-daemon + + - name: Run tests + run: ./gradlew test --no-daemon + continue-on-error: true + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: | + wallet-webapi/build/libs/*.jar + wallet-task/build/libs/*.jar + wallet-hsm/build/libs/*.jar + retention-days: 7 + + docker: + name: Docker Build + runs-on: ubuntu-latest + needs: build + if: github.ref == 'refs/heads/master' + + strategy: + matrix: + service: [wallet-webapi, wallet-task, wallet-hsm] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + file: ./${{ matrix.service }}/Dockerfile + push: false + tags: ${{ matrix.service }}:${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index c451244..011d811 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,41 @@ +# Gradle .gradle/ build/ +!gradle/wrapper/gradle-wrapper.jar + +# IDE .settings/ .project .classpath -*.class -.idea +.idea/ *.iml -.gradle -/local.properties -.DS_Store -/build +*.iws +*.ipr + +# Compiled +*.class +out/ /*/out/ -out -/wallets -/task-logs -shell -nginx -docker +# OS +.DS_Store +Thumbs.db + +# Local config +/local.properties +*.env +!.env.example + +# Application data +/wallets/ +/task-logs/ +/logs/ + +# Docker local +shell/ +nginx/ + +# Secrets - never commit +*.p12 +*.jks +*.keystore diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ebc9352..0bb389e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,6 @@ variables: DOCKER_DRIVER: overlay2 + GRADLE_OPTS: "-Dorg.gradle.daemon=false" stages: - build @@ -9,62 +10,85 @@ cache: key: ${CI_BUILD_STAGE} paths: - .gradle + - build -build for all: - image: openjdk:8-jdk-alpine +build: + image: eclipse-temurin:17-jdk-alpine tags: - wallet-dev stage: build script: - - pwd - - ./gradlew wallet-webapi:bootRepackage - - ./gradlew wallet-task:bootRepackage - - ./gradlew wallet-hsm:bootRepackage + - chmod +x ./gradlew + - ./gradlew wallet-webapi:bootJar --no-daemon -x test + - ./gradlew wallet-task:bootJar --no-daemon -x test + - ./gradlew wallet-hsm:bootJar --no-daemon -x test artifacts: paths: - wallet-webapi/build/libs/*.jar - wallet-hsm/build/libs/*.jar - wallet-task/build/libs/*.jar - expire_in: 20min + expire_in: 1 hour -deploy for cl-webapi: - image: gitlab/dind:latest +deploy wallet-webapi: + image: docker:latest + services: + - docker:dind tags: - wallet-dev stage: deploy script: - - docker stop -f wallet-webapi ||true - - docker rm -f wallet-webapi ||true - - docker rmi wallet-webapi ||true - - docker build -t wallet-webapi wallet-webapi/. - - docker run -d --name wallet-webapi -p 10001:10001 -v /etc/localtime:/etc/localtime cl-webapi + - docker stop wallet-webapi || true + - docker rm wallet-webapi || true + - docker rmi wallet-webapi || true + - docker build -t wallet-webapi -f wallet-webapi/Dockerfile . + - docker run -d --name wallet-webapi + --restart unless-stopped + -p 10001:10001 + -v /etc/localtime:/etc/localtime:ro + --env-file /etc/wallet/webapi.env + wallet-webapi when: manual -deploy for cl-task: - image: gitlab/dind:latest +deploy wallet-task: + image: docker:latest + services: + - docker:dind tags: - wallet-dev stage: deploy script: - - docker stop -f wallet-task ||true - - docker rm -f wallet-task ||true - - docker rmi wallet-task ||true - - docker build -t wallet-task wallet-task/. - - docker run -d --name wallet-task -p 10033:10033 -v /etc/localtime:/etc/localtime wallet-task + - docker stop wallet-task || true + - docker rm wallet-task || true + - docker rmi wallet-task || true + - docker build -t wallet-task -f wallet-task/Dockerfile . + - docker run -d --name wallet-task + --restart unless-stopped + -p 10033:10033 + -v /etc/localtime:/etc/localtime:ro + --env-file /etc/wallet/task.env + wallet-task when: manual -deploy for cl-hsm: - image: gitlab/dind:latest +deploy wallet-hsm: + image: docker:latest + services: + - docker:dind tags: - wallet-dev stage: deploy script: - - docker stop -f wallet-hsm ||true - - docker rm -f wallet-hsm ||true - - docker rmi wallet-hsm ||true - - docker build -t wallet-hsm wallet-hsm/. - - docker run -d --name wallet-hsm -p 10888:10888 -v /etc/localtime:/etc/localtime -v /mnt/wallets:/mnt/wallets cl-hsm + - docker stop wallet-hsm || true + - docker rm wallet-hsm || true + - docker rmi wallet-hsm || true + - docker build -t wallet-hsm -f wallet-hsm/Dockerfile . + - docker run -d --name wallet-hsm + --restart unless-stopped + -p 10888:10888 + -v /etc/localtime:/etc/localtime:ro + -v /mnt/wallets:/data/keystores + --env-file /etc/wallet/hsm.env + wallet-hsm when: manual after_script: - - echo "End CI" \ No newline at end of file + - echo "End CI" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4aa893f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -sudo: required -dist: trusty - -matrix: - include: - - os: linux - jdk: openjdk8 - - os: osx - osx_image: xcode8 - -language: java - -install: unset _JAVA_OPTIONS -script: -- chmod +x ./gradlew -- ./gradlew build - -before_cache: -- rm -f $HOME/.gradle/caches/{modules-2,transforms-1}/*.lock -- rm -rf $HOME/.gradle/caches/*/{file-changes,fileHashes,plugin-resolution,scripts,scripts-remapped,gradle-script-kotlin}/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - -notifications: - email: false \ No newline at end of file diff --git a/README.md b/README.md index 8d8ec2b..c5e8da1 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,209 @@

Java-Wallet

- - Build Status - - + Production-grade multi-chain cryptocurrency wallet backend

-## Demo Access +

+ + Build Status + + Java 17 + Kotlin + Spring Boot + Gradle + License +

-- **Backend Management:** [Link](http://34.152.57.199:10001) - - *For account access, please contact me via Telegram.* - -- **Scheduled Task Management:** [Link](http://34.152.57.199:8081/xxl-job-admin) +

+ 中文文档 · + Telegram · + Issues · + Quick Start +

- *For account access, please contact me via Telegram.* +--- ## Introduction -Java-Wallet is a powerful business system built upon the functional components of digital currency. It's designed to obtain blockchain addresses from various public chains, offering deposit and withdrawal functionalities for multiple currencies including BTC, OMNI, ETH, ERC20, TRX, TRC20, BCH, BSV, DOGE, DASH, and LTC. +Java-Wallet is a battle-tested multi-chain cryptocurrency wallet backend that has safely managed hundreds of millions of dollars in transactions in production. It provides blockchain address generation, deposit detection, withdrawal processing, and automated fund sweeping across all major public chains. + +The core signing component [tokencore](https://github.com/GalaxySciTech/tokencore) performs all cryptographic operations locally — private keys never leave the process. + +### Supported Chains + +| Chain | Native | Token | +|:------|:------:|:-----:| +| Bitcoin | BTC | OMNI (USDT) | +| Ethereum | ETH | ERC-20 | +| Tron | TRX | TRC-20 | +| Bitcoin Cash | BCH | — | +| Bitcoin SV | BSV | — | +| Litecoin | LTC | — | +| Dogecoin | DOGE | — | +| Dash | DASH | — | + +## Architecture + +``` + ┌──────────────────────────────────────────────┐ + │ Client / Admin UI │ + └──────────────────┬───────────────────────────┘ + │ HTTP + ┌───────────────────────────┼───────────────────────────┐ + │ │ │ + ┌───────▼────────┐ ┌────────▼────────┐ ┌───────▼────────┐ + │ wallet-webapi │ │ wallet-task │ │ wallet-hsm │ + │ REST API │ │ Scheduled Jobs │ │ Key Management │ + │ :10001 │ │ :10033 │ │ :10888 │ + └───────┬─────────┘ └────────┬─────────┘ └───────┬─────────┘ + │ │ │ + └────────────┬───────────────┘ │ + │ │ + ┌───────▼────────┐ ┌───────▼────────┐ + │ wallet-common │ │ wallet-entity │ + │ Business Logic │◄─────────────────────────│ JPA / Data │ + └──┬─────┬─────┬─┘ └───────┬─────────┘ + │ │ │ │ + ┌────▼┐ ┌──▼──┐ ┌▼──────┐ ┌───────▼────────┐ + │ RPC │ │ MQ │ │xxl-job│ │ MySQL 8 │ + │Nodes│ │ │ │ │ └────────────────┘ + └─────┘ └─────┘ └───────┘ +``` + +| Module | Description | +|:-------|:------------| +| **wallet-webapi** | REST API — address generation, deposits & withdrawals, admin dashboard, Swagger docs | +| **wallet-task** | Scheduled jobs — block syncing, deposit detection, auto-sweeping, fee top-up | +| **wallet-hsm** | Key management — HD wallet derivation, offline signing, key import/export | +| **wallet-common** | Shared layer — business logic, RPC clients, caching, utilities | +| **wallet-entity** | Data layer — JPA entities, repositories, QueryDSL | + +## Tech Stack + +| Category | Technology | +|:---------|:-----------| +| Language | Kotlin 1.9 + Java 17 | +| Framework | Spring Boot 3.1.3 | +| Build | Gradle 8.5 | +| Database | MySQL 8.0 · Spring Data JPA · HikariCP | +| Cache | Caffeine | +| Message Queue | RabbitMQ (Spring AMQP) | +| Task Scheduling | xxl-job 2.4.0 | +| Blockchain | [tokencore 1.3.0](https://github.com/GalaxySciTech/tokencore) · web3j 4.10.3 · bitcoin-rpc-client 1.2.4 | +| API Docs | SpringDoc OpenAPI 2.3 (Swagger UI) | +| Container | Docker multi-stage · docker-compose | +| CI/CD | GitHub Actions · GitLab CI | + +## Quick Start + +### Prerequisites + +- JDK 17+ +- MySQL 8.0+ +- RabbitMQ 3.x (required by wallet-task) + +### Docker Compose (Recommended) + +```bash +git clone https://github.com/GalaxySciTech/java-wallet.git +cd java-wallet + +cp .env.example .env # edit with your settings +docker-compose up -d +``` + +Once running: +- **API**: http://localhost:10001 +- **Swagger UI**: http://localhost:10001/swagger-ui.html +- **RabbitMQ Console**: http://localhost:15672 + +### Manual Setup + +```bash +# 1. Set environment variables (see .env.example for full list) +export DB_URL="jdbc:mysql://localhost:3306/wallet_db?useSSL=false&characterEncoding=UTF-8" +export DB_USERNAME=root +export DB_PASSWORD=your_password + +# 2. Build +chmod +x gradlew +./gradlew build -x test + +# 3. Run each service in a separate terminal +./gradlew :wallet-webapi:bootRun +./gradlew :wallet-task:bootRun +./gradlew :wallet-hsm:bootRun +``` + +## Configuration + +All sensitive values are injected via environment variables — nothing is hardcoded. See [`.env.example`](.env.example) for the full list. + +| Variable | Service | Description | +|:---------|:--------|:------------| +| `DB_URL` | webapi, task | MySQL JDBC connection URL | +| `DB_USERNAME` / `DB_PASSWORD` | webapi, task | Database credentials | +| `RABBITMQ_HOST` / `RABBITMQ_PASSWORD` | task | RabbitMQ connection | +| `KEYSTORE_DIR` / `KEYSTORE_PASSWORD` | hsm | Keystore path and password | +| `XXL_JOB_ADMIN_ADDRESSES` | task | xxl-job scheduler address | +| `WALLET_CRYPTO_PUSH_KEY` | webapi | AES key for deposit push notifications | + +## API Reference + +### Wallet API `/wallet/v1` + +| Method | Endpoint | Description | +|:------:|:---------|:------------| +| POST | `/get_address` | Generate new blockchain addresses in batch | +| POST | `/send` | Withdraw (specify `from` or auto-select from hot wallet) | +| POST | `/create_hot_address` | Create a hot wallet or gas wallet | +| POST | `/export_wallet` | Export private key or mnemonic | +| POST | `/import_wallet` | Import private key or mnemonic | +| GET | `/get_hot_address` | Query hot wallet addresses | +| GET | `/check_address` | Check if address private key exists | +| GET | `/get_transaction` | Query deposit / withdrawal / sweep records | +| GET | `/get_new_deposit` | Fetch new deposits (marked as read after fetch) | +| GET | `/check_tx_status` | Check on-chain transaction status | + +### Blockchain API `/block_chain/v1` + +| Method | Endpoint | Description | +|:------:|:---------|:------------| +| GET | `/get_transaction` | Query on-chain transaction details | +| GET | `/get_address_balance` | Query on-chain address balance | +| GET | `/get_recommend_fee` | Get recommended fees (slow / medium / fast) | +| GET | `/calculation_fee` | Calculate transaction fee | +| GET | `/get_support_token` | List all supported tokens | + +### Admin API `/admin` + +| Method | Endpoint | Description | +|:------:|:---------|:------------| +| POST | `/login` | Admin login | +| GET | `/get_dashboard` | Dashboard overview | +| GET | `/get_addr_list` | Address list | +| GET | `/get_token_list` | Token list | +| POST | `/edit_token` | Edit token configuration | +| POST | `/edit_config` | Edit system configuration | +| POST | `/edit_white` | Edit IP whitelist | + +> Full interactive API docs are available at Swagger UI after starting the service. -**Key Features:** -- Dynamic retrieval of blockchain addresses. -- Seamless deposit and withdrawal functions for multiple cryptocurrencies. -- API-centric design for easy integration. - -**Technical Highlights:** -- Developed using the SpringBoot framework. -- Written in Java and Kotlin. -- Utilizes RabbitMQ for messaging. -- Employs MySQL for cloud database management. -- Integrates xxl-job for distributed scheduled tasks. +## Reliability -## Architecture Overview +Java-Wallet has been running in production and has safely processed hundreds of millions of dollars in transactions. It is built for high reliability, scalability, and real-world utility. -![Code Sample](https://i.ibb.co/PD2zRPD/We-Chate0ef7be708d49975ed0d411eb4194a47.png) -![Backend Management](https://i.ibb.co/zb8LtyH/test.gif) -![API Interface](https://i.ibb.co/MPbh9Gj/test1.gif) +## Contact -## Reliability +For technical support, business inquiries, or deployment consulting: -Java-Wallet is a robust platform that has been rigorously tested, having managed transactions worth hundreds of millions of dollars in a production environment. It boasts high reliability, scalability, and utility, ensuring confidence in its deployment and use. +**[@GalaxySciTech](https://t.me/GalaxySciTech)** on Telegram -## Support +## Disclaimer -If you encounter any issues or require further clarification, feel free to [submit an issue](https://github.com/galaxyscitech/java-wallet/issues). +Any commercial use of this source code is at your own risk. The authors assume no liability for any losses incurred by yourself or others. -## Disclaimer +## License -Please note that any commercial activities pursued using this source code, which result in losses (either to oneself or to others), are the sole responsibility of the user. I hold no liability for such outcomes. +This project is provided as-is. See the repository for license details. diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..026ae0c --- /dev/null +++ b/README_CN.md @@ -0,0 +1,209 @@ +

Java-Wallet

+ +

+ 生产级多链加密货币钱包后台系统 +

+ +

+ + 构建状态 + + Java 17 + Kotlin + Spring Boot + Gradle + License +

+ +

+ English · + Telegram · + Issues · + 快速开始 +

+ +--- + +## 简介 + +Java-Wallet 是一套经过生产环境验证的多链加密货币钱包后台系统,曾稳定管理过数亿美元级别的交易。系统提供区块链地址生成、充值检测、提现处理和自动归集等核心功能,支持主流公链和代币。 + +核心签名组件 [tokencore](https://github.com/GalaxySciTech/tokencore) 支持全链离线签名,私钥全程本地运算,从不外泄。 + +### 支持的公链 + +| 公链 | 原生币 | 代币 | +|:-----|:------:|:----:| +| Bitcoin | BTC | OMNI (USDT) | +| Ethereum | ETH | ERC-20 | +| Tron | TRX | TRC-20 | +| Bitcoin Cash | BCH | — | +| Bitcoin SV | BSV | — | +| Litecoin | LTC | — | +| Dogecoin | DOGE | — | +| Dash | DASH | — | + +## 系统架构 + +``` + ┌──────────────────────────────────────────────┐ + │ 客户端 / 管理后台 UI │ + └──────────────────┬───────────────────────────┘ + │ HTTP + ┌───────────────────────────┼───────────────────────────┐ + │ │ │ + ┌───────▼────────┐ ┌────────▼────────┐ ┌───────▼────────┐ + │ wallet-webapi │ │ wallet-task │ │ wallet-hsm │ + │ REST 接口 │ │ 定时任务 │ │ 密钥管理 │ + │ :10001 │ │ :10033 │ │ :10888 │ + └───────┬─────────┘ └────────┬─────────┘ └───────┬─────────┘ + │ │ │ + └────────────┬───────────────┘ │ + │ │ + ┌───────▼────────┐ ┌───────▼────────┐ + │ wallet-common │ │ wallet-entity │ + │ 业务逻辑 │◄─────────────────────────│ 数据访问层 │ + └──┬─────┬─────┬─┘ └───────┬─────────┘ + │ │ │ │ + ┌────▼┐ ┌──▼──┐ ┌▼──────┐ ┌───────▼────────┐ + │ RPC │ │ MQ │ │xxl-job│ │ MySQL 8 │ + │ 节点 │ │ │ │ │ └────────────────┘ + └─────┘ └─────┘ └───────┘ +``` + +| 模块 | 说明 | +|:-----|:-----| +| **wallet-webapi** | REST API — 地址生成、充提币、管理后台、Swagger 文档 | +| **wallet-task** | 定时任务 — 区块同步、充值检测、自动归集、手续费补发 | +| **wallet-hsm** | 密钥管理 — HD 钱包派生、离线签名、私钥导入导出 | +| **wallet-common** | 公共层 — 业务逻辑、RPC 客户端、缓存、工具类 | +| **wallet-entity** | 数据层 — JPA 实体、Repository、QueryDSL | + +## 技术栈 + +| 类别 | 技术 | +|:-----|:-----| +| 语言 | Kotlin 1.9 + Java 17 | +| 框架 | Spring Boot 3.1.3 | +| 构建 | Gradle 8.5 | +| 数据库 | MySQL 8.0 · Spring Data JPA · HikariCP | +| 缓存 | Caffeine | +| 消息队列 | RabbitMQ (Spring AMQP) | +| 任务调度 | xxl-job 2.4.0 | +| 区块链 | [tokencore 1.3.0](https://github.com/GalaxySciTech/tokencore) · web3j 4.10.3 · bitcoin-rpc-client 1.2.4 | +| 接口文档 | SpringDoc OpenAPI 2.3 (Swagger UI) | +| 容器化 | Docker 多阶段构建 · docker-compose | +| CI/CD | GitHub Actions · GitLab CI | + +## 快速开始 + +### 环境要求 + +- JDK 17+ +- MySQL 8.0+ +- RabbitMQ 3.x(wallet-task 需要) + +### Docker Compose(推荐) + +```bash +git clone https://github.com/GalaxySciTech/java-wallet.git +cd java-wallet + +cp .env.example .env # 编辑配置 +docker-compose up -d +``` + +服务启动后: +- **API 接口**: http://localhost:10001 +- **Swagger 文档**: http://localhost:10001/swagger-ui.html +- **RabbitMQ 管理**: http://localhost:15672 + +### 手动部署 + +```bash +# 1. 配置环境变量(完整列表见 .env.example) +export DB_URL="jdbc:mysql://localhost:3306/wallet_db?useSSL=false&characterEncoding=UTF-8" +export DB_USERNAME=root +export DB_PASSWORD=your_password + +# 2. 构建项目 +chmod +x gradlew +./gradlew build -x test + +# 3. 启动服务(分别在不同终端运行) +./gradlew :wallet-webapi:bootRun +./gradlew :wallet-task:bootRun +./gradlew :wallet-hsm:bootRun +``` + +## 配置说明 + +所有敏感配置均通过环境变量注入,绝不硬编码在代码中。完整列表见 [`.env.example`](.env.example)。 + +| 变量 | 服务 | 说明 | +|:-----|:-----|:-----| +| `DB_URL` | webapi, task | MySQL JDBC 连接地址 | +| `DB_USERNAME` / `DB_PASSWORD` | webapi, task | 数据库用户名和密码 | +| `RABBITMQ_HOST` / `RABBITMQ_PASSWORD` | task | RabbitMQ 连接信息 | +| `KEYSTORE_DIR` / `KEYSTORE_PASSWORD` | hsm | 密钥库存储路径与密码 | +| `XXL_JOB_ADMIN_ADDRESSES` | task | xxl-job 调度中心地址 | +| `WALLET_CRYPTO_PUSH_KEY` | webapi | 充值推送通知 AES 加密密钥 | + +## 接口文档 + +### 钱包接口 `/wallet/v1` + +| 方法 | 路径 | 说明 | +|:----:|:-----|:-----| +| POST | `/get_address` | 批量生成区块链地址 | +| POST | `/send` | 提现(可指定 from 地址,不指定则自动从热钱包转出) | +| POST | `/create_hot_address` | 创建热钱包 / Gas 钱包地址 | +| POST | `/export_wallet` | 导出私钥或助记词 | +| POST | `/import_wallet` | 导入私钥或助记词 | +| GET | `/get_hot_address` | 查询热钱包地址 | +| GET | `/check_address` | 验证地址私钥是否存在 | +| GET | `/get_transaction` | 查询充值/提现/归集记录 | +| GET | `/get_new_deposit` | 获取新充值记录(拉取后自动标记已读) | +| GET | `/check_tx_status` | 查询链上交易状态 | + +### 区块链接口 `/block_chain/v1` + +| 方法 | 路径 | 说明 | +|:----:|:-----|:-----| +| GET | `/get_transaction` | 链上查询交易详情 | +| GET | `/get_address_balance` | 链上查询地址余额 | +| GET | `/get_recommend_fee` | 获取推荐手续费(低速/中速/快速) | +| GET | `/calculation_fee` | 计算交易手续费 | +| GET | `/get_support_token` | 获取支持的币种列表 | + +### 管理后台接口 `/admin` + +| 方法 | 路径 | 说明 | +|:----:|:-----|:-----| +| POST | `/login` | 管理员登录 | +| GET | `/get_dashboard` | 获取仪表盘概览数据 | +| GET | `/get_addr_list` | 获取地址列表 | +| GET | `/get_token_list` | 获取代币列表 | +| POST | `/edit_token` | 编辑代币配置 | +| POST | `/edit_config` | 编辑系统配置 | +| POST | `/edit_white` | 编辑 IP 白名单 | + +> 完整的交互式接口文档请在启动服务后访问 Swagger UI。 + +## 可靠性 + +Java-Wallet 已在生产环境中长期稳定运行,安全管理过数亿美元的交易量。系统具备高可靠性、可扩展性和实用性,值得信赖。 + +## 联系我们 + +如需技术支持、商业合作或部署咨询,请通过 Telegram 联系: + +**[@GalaxySciTech](https://t.me/GalaxySciTech)** + +## 免责声明 + +使用本源代码进行的任何商业活动,由此产生的损失(无论是对自己还是对他人)均由使用者自行承担,作者不对此承担任何责任。 + +## 许可证 + +本项目按原样提供,详见仓库中的许可证文件。 diff --git a/build.gradle b/build.gradle index ae59870..5904868 100644 --- a/build.gradle +++ b/build.gradle @@ -8,9 +8,9 @@ allprojects { } repositories { mavenLocal() - maven {url 'https://maven.aliyun.com/repository/public/'} + maven { url 'https://maven.aliyun.com/repository/public/' } maven { url 'https://jitpack.io' } - maven { url "https://kotlin.bintray.com/kotlinx" } + mavenCentral() } tasks.withType(JavaCompile) { @@ -32,13 +32,13 @@ subprojects { apply plugin: 'org.springframework.boot' apply plugin: "io.spring.dependency-management" - sourceCompatibility = 1.8 + sourceCompatibility = 17 compileKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "17" } compileTestKotlin { - kotlinOptions.jvmTarget = "1.8" + kotlinOptions.jvmTarget = "17" } tasks.withType(JavaCompile) { @@ -46,65 +46,34 @@ subprojects { } -// dependencyManagement { -// imports { -// mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Dalston.RELEASE' -// } -// } - - dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" - compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3" - compile "org.springframework.boot:spring-boot-starter-web:$springBootVersion" - compile "org.springframework.boot:spring-boot-starter-cache:$springBootVersion" - compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" - compile 'com.zaxxer:HikariCP:5.0.1' - compile 'mysql:mysql-connector-java:5.1.40' -// compile "org.springframework.boot:spring-boot-devtools:$springBootVersion" - compile 'org.apache.commons:commons-lang3:3.8.1' - compileOnly 'org.projectlombok:lombok:1.18.6' - compile 'commons-beanutils:commons-beanutils:1.9.4' -// compile "org.springframework.boot:spring-boot-starter-data-redis:$springBootVersion" - compile 'org.web3j:core:4.2.0' - compile 'wf.bitcoin:bitcoin-rpc-client:1.1.0' -// compile 'com.github.EOSEssentials:eos-java-rpc-wrapper:master' - - // API Doc Generator: Swagger - compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.6.1' - compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.6.1' - compile "org.springframework.boot:spring-boot-starter-amqp:$springBootVersion" - compile 'com.github.ben-manes.caffeine:caffeine:3.1.8' - compile 'com.github.sealedtx:bitcoin-cash-converter:1.0' - compile 'com.xuxueli:xxl-job-core:2.4.0' - //ALI SDK -// compile 'com.aliyun:aliyun-java-sdk-core:4.0.3' -// //AWS SDK -// compile("net.minidev:json-smart:2.2.1") -// compile("com.amazonaws:aws-java-sdk:1.11.401") { -// exclude module: "net.minidev" -// compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1' -// } - compile 'com.github.TraderGalax:tokencore:1.2.7' - testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion" - + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3" + implementation "org.springframework.boot:spring-boot-starter-web:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-cache:$springBootVersion" + implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" + implementation 'com.zaxxer:HikariCP:5.0.1' + implementation 'com.mysql:mysql-connector-j:8.2.0' + implementation 'org.apache.commons:commons-lang3:3.14.0' + compileOnly 'org.projectlombok:lombok:1.18.30' + annotationProcessor 'org.projectlombok:lombok:1.18.30' + implementation 'commons-beanutils:commons-beanutils:1.9.4' + implementation 'org.web3j:core:4.10.3' + implementation 'wf.bitcoin:bitcoin-rpc-client:1.2.4' + + implementation "org.springframework.boot:spring-boot-starter-amqp:$springBootVersion" + implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8' + implementation 'com.github.sealedtx:bitcoin-cash-converter:1.0' + implementation 'com.xuxueli:xxl-job-core:2.4.0' + implementation 'com.github.GalaxySciTech:tokencore:1.3.0' + + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + + testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion" } -// configurations{ -// compileJava.exclude module: 'spring-boot-starter-tomcat' -// } -// task "create-dirs" << { -// sourceSets*.java.srcDirs*.each{ -// it.mkdirs() -// } -// sourceSets*.kotlin.srcDirs*.each{ -// it.mkdirs() -// } -// sourceSets*.resources.srcDirs*.each{ -// it.mkdirs() -// } -// } + } buildscript { @@ -113,12 +82,12 @@ buildscript { ext.springBootVersion = '3.1.3' repositories { - maven {url 'https://maven.aliyun.com/repository/public/'} + maven { url 'https://maven.aliyun.com/repository/public/' } mavenLocal() mavenCentral() } dependencies { - classpath "io.spring.gradle:dependency-management-plugin:1.0.3.RELEASE" + classpath "io.spring.gradle:dependency-management-plugin:1.1.4" classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..43b500c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,81 @@ +version: '3.8' + +services: + mysql: + image: mysql:8.0 + environment: + MYSQL_ROOT_PASSWORD: ${DB_PASSWORD:-devpassword} + MYSQL_DATABASE: wallet_db + ports: + - "3306:3306" + volumes: + - mysql_data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 10s + timeout: 5s + retries: 5 + + rabbitmq: + image: rabbitmq:3-management-alpine + environment: + RABBITMQ_DEFAULT_USER: ${RABBITMQ_USERNAME:-guest} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-guest} + ports: + - "5672:5672" + - "15672:15672" + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"] + interval: 10s + timeout: 5s + retries: 5 + + wallet-webapi: + build: + context: . + dockerfile: wallet-webapi/Dockerfile + ports: + - "10001:10001" + environment: + DB_URL: jdbc:mysql://mysql:3306/wallet_db?allowMultiQueries=true&useSSL=false&characterEncoding=UTF-8&autoReconnect=true + DB_USERNAME: root + DB_PASSWORD: ${DB_PASSWORD:-devpassword} + depends_on: + mysql: + condition: service_healthy + + wallet-task: + build: + context: . + dockerfile: wallet-task/Dockerfile + ports: + - "10033:10033" + environment: + DB_URL: jdbc:mysql://mysql:3306/wallet_db?allowMultiQueries=true&useSSL=false&characterEncoding=UTF-8&autoReconnect=true + DB_USERNAME: root + DB_PASSWORD: ${DB_PASSWORD:-devpassword} + RABBITMQ_HOST: rabbitmq + RABBITMQ_PORT: 5672 + RABBITMQ_USERNAME: ${RABBITMQ_USERNAME:-guest} + RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD:-guest} + depends_on: + mysql: + condition: service_healthy + rabbitmq: + condition: service_healthy + + wallet-hsm: + build: + context: . + dockerfile: wallet-hsm/Dockerfile + ports: + - "10888:10888" + environment: + KEYSTORE_DIR: /data/keystores + KEYSTORE_PASSWORD: ${KEYSTORE_PASSWORD:-} + volumes: + - keystore_data:/data/keystores + +volumes: + mysql_data: + keystore_data: diff --git a/gradle.properties b/gradle.properties index 694b686..2b83233 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,18 +1,14 @@ -# Gradle 编译配置 -#开启gradle并行编译,开启daemon,调整jvm内存大小 +# Gradle build configuration org.gradle.daemon=true org.gradle.configureondemand=true org.gradle.parallel=true -org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=256m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -#开启gradle缓存 +# Gradle caching org.gradle.caching=true -android.enableBuildCache=true -#开启kotlin的增量和并行编译 +# Kotlin incremental and parallel compilation kotlin.incremental=true kotlin.incremental.java=true -kotlin.incremental.js=true kotlin.caching.enabled=true -#开启kotlin并行编译 kotlin.parallel.tasks.in.project=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ecd525e..0cea8ae 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ -#Thu Apr 11 15:34:58 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true diff --git a/wallet-common/build.gradle b/wallet-common/build.gradle index 97084fc..a16cce5 100644 --- a/wallet-common/build.gradle +++ b/wallet-common/build.gradle @@ -1,7 +1,6 @@ -bootRepackage.enabled=false - +bootJar.enabled = false +jar.enabled = true dependencies { - compile project(":wallet-entity") + implementation project(":wallet-entity") } - diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/cache/impl/CacheServiceImpl.kt b/wallet-common/src/main/kotlin/com/wallet/biz/cache/impl/CacheServiceImpl.kt index d6a2ae7..ae3a493 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/cache/impl/CacheServiceImpl.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/cache/impl/CacheServiceImpl.kt @@ -15,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.cache.annotation.Cacheable import org.springframework.stereotype.Service import org.web3j.protocol.core.DefaultBlockParameterName -import javax.annotation.PostConstruct +import jakarta.annotation.PostConstruct import kotlin.collections.HashMap /**
 diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/config/AsyncConfig.kt b/wallet-common/src/main/kotlin/com/wallet/biz/config/AsyncConfig.kt index 782c2eb..5ae9c1c 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/config/AsyncConfig.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/config/AsyncConfig.kt @@ -1,11 +1,8 @@ package com.wallet.biz.config +import org.springframework.context.annotation.Configuration import org.springframework.scheduling.annotation.EnableAsync -/**
 - * Created by pie on 2020/2/7 16: 40.
 - */ +@Configuration @EnableAsync -class AsyncConfig { - -} \ No newline at end of file +open class AsyncConfig diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/config/CacheConfig.kt b/wallet-common/src/main/kotlin/com/wallet/biz/config/CacheConfig.kt index 4b7af55..88a5c88 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/config/CacheConfig.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/config/CacheConfig.kt @@ -1,19 +1,13 @@ package com.wallet.biz.config -import com.wallet.biz.cache.CacheService import com.github.benmanes.caffeine.cache.Caffeine -import org.springframework.beans.factory.annotation.Autowired import org.springframework.cache.CacheManager import org.springframework.cache.annotation.EnableCaching import org.springframework.cache.caffeine.CaffeineCacheManager import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import java.util.concurrent.TimeUnit -import javax.annotation.PostConstruct -/**
 - * Created by pie on 2020/7/24 02: 59.
 - */ @Configuration @EnableCaching open class CacheConfig { @@ -22,11 +16,11 @@ open class CacheConfig { open fun cacheManager(): CacheManager { val caffeine = Caffeine.newBuilder() .initialCapacity(100) - .maximumSize(1000) - .expireAfterWrite(3, TimeUnit.SECONDS) + .maximumSize(5000) + .expireAfterWrite(30, TimeUnit.SECONDS) + .recordStats() val cacheManager = CaffeineCacheManager() cacheManager.setCaffeine(caffeine) return cacheManager } - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/config/DbOp.kt b/wallet-common/src/main/kotlin/com/wallet/biz/config/DbOp.kt index ee6ff62..73a5214 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/config/DbOp.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/config/DbOp.kt @@ -4,19 +4,17 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.jdbc.core.JdbcTemplate import org.springframework.stereotype.Component - -/**
 - * Created by pie on 2020/11/1 16: 13.
 - */ @Component class DbOp { - fun select(sql: String): List> { - return jdbcTemplate.queryForList(sql) + fun select(sql: String, vararg args: Any): List> { + return if (args.isEmpty()) { + jdbcTemplate.queryForList(sql) + } else { + jdbcTemplate.queryForList(sql, *args) + } } @Autowired lateinit var jdbcTemplate: JdbcTemplate - - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/config/RestTemplateConfig.kt b/wallet-common/src/main/kotlin/com/wallet/biz/config/RestTemplateConfig.kt index bfe4495..bfef636 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/config/RestTemplateConfig.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/config/RestTemplateConfig.kt @@ -6,27 +6,24 @@ import org.springframework.context.annotation.Configuration import org.springframework.http.MediaType import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter import org.springframework.web.client.RestTemplate +import java.time.Duration - -/**
 - * Created by pie on 2019-03-05 13: 41.
 - */ @Configuration open class RestTemplateConfig { @Bean open fun rest(restTemplateBuilder: RestTemplateBuilder): RestTemplate { - val restTemplate= restTemplateBuilder.build() - restTemplate.messageConverters.add(WxMappingJackson2HttpMessageConverter()) + val restTemplate = restTemplateBuilder + .connectTimeout(Duration.ofSeconds(10)) + .readTimeout(Duration.ofSeconds(30)) + .build() + restTemplate.messageConverters.add(OctetStreamJsonConverter()) return restTemplate } - class WxMappingJackson2HttpMessageConverter : MappingJackson2HttpMessageConverter() { + private class OctetStreamJsonConverter : MappingJackson2HttpMessageConverter() { init { - val mediaTypes: MutableList = ArrayList() - mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM) - supportedMediaTypes = mediaTypes // tag6 + supportedMediaTypes = listOf(MediaType.APPLICATION_OCTET_STREAM) } } - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/config/SwaggerConfig.kt b/wallet-common/src/main/kotlin/com/wallet/biz/config/SwaggerConfig.kt index f6988a5..8511072 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/config/SwaggerConfig.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/config/SwaggerConfig.kt @@ -1,59 +1,38 @@ package com.wallet.biz.config +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.info.License +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.security.SecurityScheme +import io.swagger.v3.oas.models.security.SecurityRequirement import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.web.context.request.async.DeferredResult -import springfox.documentation.builders.ApiInfoBuilder -import springfox.documentation.builders.RequestHandlerSelectors -import springfox.documentation.service.ApiInfo -import springfox.documentation.service.Contact -import springfox.documentation.spi.DocumentationType -import springfox.documentation.spring.web.plugins.Docket -import springfox.documentation.swagger2.annotations.EnableSwagger2 -import springfox.documentation.schema.ModelRef -import java.util.ArrayList -import springfox.documentation.builders.ParameterBuilder -import springfox.documentation.service.Parameter - -/** - * Created by zhangxinglin on 2017/7/28. - */ @Configuration -@EnableSwagger2 open class SwaggerConfig { @Bean - open fun api(): Docket{ - val ticketPar = ParameterBuilder() - val pars = ArrayList() - ticketPar.name("access_token").description("access_token") - .modelRef(ModelRef("string")).parameterType("header") - .required(false).build() //header中的ticket参数非必填,传空也可以 - pars.add(ticketPar.build()) //根据每个方法名也知道当前方法在设置什么参数 - - return Docket(DocumentationType.SWAGGER_2) - .enable(true) - .globalOperationParameters(pars) - .genericModelSubstitutes(DeferredResult::class.java) - .useDefaultResponseMessages(false) - .forCodeGeneration(false) - .pathMapping("/") // base,最终调用接口后会和paths拼接在一起 - .select() - .apis(RequestHandlerSelectors.basePackage("com.wallet")) - .build() - .apiInfo(loanApiInfo()) - } - - private fun loanApiInfo(): ApiInfo { - return ApiInfoBuilder() - .title("token API")//大标题 - .description("token's REST API, all the applications could assess the Object model data via JSON.")//详细描述 - .version("2.1.3.11")//版本 - .termsOfServiceUrl("NO terms of service") - //.contact(Contact("PIE", "https://github.com/pai01234", "dengrunali@gmail.com"))//作者 - .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") - .build() - + open fun openAPI(): OpenAPI { + val securitySchemeName = "access_token" + return OpenAPI() + .info( + Info() + .title("Java-Wallet API") + .description("Multi-chain cryptocurrency wallet REST API") + .version("3.0.0") + .license(License().name("Apache 2.0").url("http://www.apache.org/licenses/LICENSE-2.0.html")) + ) + .addSecurityItem(SecurityRequirement().addList(securitySchemeName)) + .components( + Components() + .addSecuritySchemes( + securitySchemeName, + SecurityScheme() + .name(securitySchemeName) + .type(SecurityScheme.Type.APIKEY) + .`in`(SecurityScheme.In.HEADER) + ) + ) } } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/config/globalhandler/GlobalHandler.kt b/wallet-common/src/main/kotlin/com/wallet/biz/config/globalhandler/GlobalHandler.kt index df2e477..b332f38 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/config/globalhandler/GlobalHandler.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/config/globalhandler/GlobalHandler.kt @@ -3,46 +3,40 @@ package com.wallet.hsm.config.globalhandler import com.wallet.biz.dict.SysConfigKey import com.wallet.biz.domain.dict.TokenResponse import com.wallet.biz.domain.exception.BizException +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice import wf.bitcoin.javabitcoindrpcclient.BitcoinRPCException -import javax.servlet.http.HttpServletRequest @RestControllerAdvice class GlobalHandler { + private val logger = LoggerFactory.getLogger(GlobalHandler::class.java) + @ExceptionHandler(Exception::class) fun handleException(e: Exception): TokenResponse { - val message = when (cacheService.getSysConfig(SysConfigKey.ERROR_LEVEL).toIntOrNull()?:0) { - 0 -> e.message.toString() - else -> e.stackTrace.joinToString(" ") + logger.error("Unhandled exception: ${e.message}", e) + val message = when (cacheService.getSysConfig(SysConfigKey.ERROR_LEVEL).toIntOrNull() ?: 0) { + 0 -> e.message ?: "Internal server error" + else -> e.message ?: "Internal server error" } - return TokenResponse(-1, message, "") } @ExceptionHandler(BizException::class) fun handleException(e: BizException): TokenResponse { - val message = when (cacheService.getSysConfig(SysConfigKey.ERROR_LEVEL).toIntOrNull()?:0) { - 0 -> e.message.toString() - else -> e.stackTrace.joinToString(" ") - } - - return TokenResponse(e.code, message, "") + logger.warn("Business exception: code=${e.code}, message=${e.message}") + return TokenResponse(e.code, e.message ?: "Business error", "") } @ExceptionHandler(BitcoinRPCException::class) fun handleBizException(e: BitcoinRPCException): TokenResponse { - - return TokenResponse(e.rpcError.code, e.rpcError.message, "") + logger.error("Bitcoin RPC exception: ${e.rpcError?.message}", e) + return TokenResponse(e.rpcError?.code ?: -1, e.rpcError?.message ?: "RPC error", "") } - @Autowired - lateinit var request: HttpServletRequest @Autowired lateinit var cacheService: com.wallet.biz.cache.CacheService - - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/dict/HsmReuqestType.kt b/wallet-common/src/main/kotlin/com/wallet/biz/dict/HsmReuqestType.kt index e1c1048..56557a8 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/dict/HsmReuqestType.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/dict/HsmReuqestType.kt @@ -1,28 +1,25 @@ package com.wallet.biz.dict -/**
 - * Created by pie on 2019-04-13 15: 34.
 - */ -object HsmReuqestType{ - const val DERIVE_WALLETS="/hsm/deriveWallets" +object HsmReuqestType { + const val DERIVE_WALLETS = "/hsm/deriveWallets" - const val SIGN_USDT_TRANSACTION="/hsm/sign_usdt_transaction" + const val SIGN_USDT_TRANSACTION = "/hsm/sign_usdt_transaction" - const val SIGN_BTC_TRANSACTION="/hsm/sign_bitcoin_transaction" + const val SIGN_BTC_TRANSACTION = "/hsm/sign_bitcoin_transaction" - const val SIGN_BCH_TRANSACTION="/hsm/sign_bitcoin_cash_transaction" + const val SIGN_BCH_TRANSACTION = "/hsm/sign_bitcoin_cash_transaction" - const val SIGN_ETH_TRANSACTION="/hsm/sign_ethereum_transaction" + const val SIGN_ETH_TRANSACTION = "/hsm/sign_ethereum_transaction" - const val SIGN_USDT_COLLECT_TRANSACTION="/hsm/sign_usdt_collect_transaction" + const val SIGN_USDT_COLLECT_TRANSACTION = "/hsm/sign_usdt_collect_transaction" - const val CHECK_WALLET="/hsm/check_wallet" + const val CHECK_WALLET = "/hsm/check_wallet" - const val EXPORT_WALLET="/hsm/export_wallet" + const val EXPORT_WALLET = "/hsm/export_wallet" - const val IMPORT_WALLET="/hsm/import_wallet" + const val IMPORT_WALLET = "/hsm/import_wallet" - const val REMOVE_USELESS_WALLET="/hsm/remove_useless_wallet" + const val REMOVE_USELESS_WALLET = "/hsm/remove_useless_wallet" - const val GET_ALL_WALLETS="/hsm/remove_useless_wallet" + const val GET_ALL_WALLETS = "/hsm/get_all_wallets" } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/dict/RegexType.kt b/wallet-common/src/main/kotlin/com/wallet/biz/dict/RegexType.kt index bb48eeb..1d33e94 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/dict/RegexType.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/dict/RegexType.kt @@ -1,13 +1,9 @@ package com.wallet.biz.dict -/**
 - * Created by pie on 2019-03-12 17: 42.
 - */ object RegexType { - const val PWD_REGEX="/^[\\w_-]{6,16}\$/" + const val PWD_REGEX = "^[\\w_-]{6,16}\$" - const val TRADE_PWD_REGEX="/^[\\w_-]{6}\$/" + const val TRADE_PWD_REGEX = "^[\\w_-]{6}\$" - -} \ No newline at end of file +} diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/handler/service/impl/SynServiceImpl.kt b/wallet-common/src/main/kotlin/com/wallet/biz/handler/service/impl/SynServiceImpl.kt index b9c3413..9484293 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/handler/service/impl/SynServiceImpl.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/handler/service/impl/SynServiceImpl.kt @@ -20,9 +20,9 @@ import org.web3j.protocol.core.DefaultBlockParameterNumber import org.web3j.protocol.core.methods.response.EthBlock import wf.bitcoin.javabitcoindrpcclient.BitcoinJSONRPCClient import java.math.BigDecimal +import org.slf4j.LoggerFactory import java.util.* import java.util.concurrent.Executors -import javax.annotation.PostConstruct /**
 * Created by pie on 2019-04-12 14: 03.
 @@ -30,6 +30,8 @@ import javax.annotation.PostConstruct @Service class SynServiceImpl : SynService { + private val logger = LoggerFactory.getLogger(SynServiceImpl::class.java) + override fun synOMNI() { @@ -79,10 +81,9 @@ class SynServiceImpl : SynService { val addressInDb = walletXService.checkAddressInDb(map, tx.referenceaddress) if (addressInDb) { - walletAddressTransactionService.getByHash(tx.txid!!)?.let { tx -> - - tx.confirmations = tx.confirmations!!.toLong() - walletAddressTransactionService.save(tx) + walletAddressTransactionService.getByHash(tx.txid!!)?.let { existingDeposit -> + existingDeposit.confirmations = tx.confirmations!!.toLong() + walletAddressTransactionService.save(existingDeposit) return@forEach } val transaction = Deposit() @@ -148,12 +149,10 @@ class SynServiceImpl : SynService { val contractMap = walletTokenService.getByBean(walletToken).associateBy { it.tokenAddress } walletHeight.height = scanHeight if (map.isEmpty()) { - walletBlockHeightService.save(walletHeight) - return + continue } - val ethBlock = ethRpc.ethGetBlockByNumber( DefaultBlockParameterNumber(scanHeight), true ).send() @@ -420,22 +419,27 @@ class SynServiceImpl : SynService { override fun synImportAddress() { val executor = Executors.newFixedThreadPool(10) val list = walletWaitImportService.findAll() - list.forEach { - executor.execute { - try { - when (it.chainType) { - ChainType.BITCOIN -> importAddress(rpcClient.omniRpc(), it.address, false) - ChainType.LITECOIN -> importAddress(rpcClient.ltcRpc(), it.address, false) - ChainType.BITCOINSV -> importAddress(rpcClient.bsvRpc(), it.address, false) - ChainType.DOGECOIN -> importAddress(rpcClient.dogeRpc(), it.address, false) - ChainType.BITCOINCASH -> importAddress(rpcClient.bchRpc(), it.address, false) - ChainType.DASH -> importAddress(rpcClient.dashRpc(), it.address, false) + try { + list.forEach { + executor.execute { + try { + when (it.chainType) { + ChainType.BITCOIN -> importAddress(rpcClient.omniRpc(), it.address, false) + ChainType.LITECOIN -> importAddress(rpcClient.ltcRpc(), it.address, false) + ChainType.BITCOINSV -> importAddress(rpcClient.bsvRpc(), it.address, false) + ChainType.DOGECOIN -> importAddress(rpcClient.dogeRpc(), it.address, false) + ChainType.BITCOINCASH -> importAddress(rpcClient.bchRpc(), it.address, false) + ChainType.DASH -> importAddress(rpcClient.dashRpc(), it.address, false) + } + walletWaitImportService.deleteById(it.id) + } catch (e: Exception) { + logger.error("Failed to import address ${it.address} for ${it.chainType}: ${e.message}") } - walletWaitImportService.deleteById(it.id) - } catch (e: Exception) { - } } + } finally { + executor.shutdown() + executor.awaitTermination(5, java.util.concurrent.TimeUnit.MINUTES) } } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/log/impl/LogService.kt b/wallet-common/src/main/kotlin/com/wallet/biz/log/impl/LogService.kt index c34a433..9415ba9 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/log/impl/LogService.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/log/impl/LogService.kt @@ -1,22 +1,29 @@ package com.wallet.biz.log.impl -import org.springframework.stereotype.Service +import org.slf4j.LoggerFactory -/**
 - * Created by pie on 2020/7/31 12: 35.
 - */ -open class LogService { +open class LogService { - fun log(str: String?) { + private val logger = LoggerFactory.getLogger(this.javaClass) + fun log(str: String?) { + if (str != null) { + logger.info(str) + } } fun log(str: String?, level: Int) { - + if (str == null) return + when (level) { + 0 -> logger.debug(str) + 1 -> logger.info(str) + 2 -> logger.warn(str) + 3 -> logger.error(str) + else -> logger.info(str) + } } fun log(map: HashMap) { - + logger.info("Operation: {}", map) } - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/mq/PushComponent.kt b/wallet-common/src/main/kotlin/com/wallet/biz/mq/PushComponent.kt index 40d980a..36be1b6 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/mq/PushComponent.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/mq/PushComponent.kt @@ -5,23 +5,24 @@ import com.wallet.biz.dict.MqKey import com.wallet.biz.dict.SysConfigKey import com.wallet.biz.domain.dict.ErrorCode import com.wallet.biz.domain.exception.BizException -import com.fasterxml.jackson.databind.ObjectMapper import com.wallet.biz.log.impl.LogService import com.wallet.biz.utils.Crypto import org.springframework.amqp.core.AmqpTemplate import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate -import java.lang.StringBuilder -import java.util.* -/**
 - * Created by pie on 2019-04-15 17: 40.
 - */ @Component class PushComponent : LogService() { - val pass = "25779fb0-d804-4a16-a465-e7c449b0" + @Value("\${wallet.crypto.push-key:#{null}}") + private var pushEncryptionKey: String? = null + + private fun getEncryptionKey(): String { + return pushEncryptionKey + ?: throw BizException(ErrorCode.ERROR_PARAM, "Push encryption key not configured (wallet.crypto.push-key)") + } fun sendMsgToMq(msg: String) { amqpTemplate.convertAndSend(MqKey.TOPIC_EXCHANGE, MqKey.DEPOSIT_KEY, msg) @@ -29,16 +30,15 @@ class PushComponent : LogService() { fun sendMsgToService(msg: String) { log("推送充值记录到post") - val enMsg = Crypto.aesEncrypt(msg, pass) + val enMsg = Crypto.aesEncrypt(msg, getEncryptionKey()) val url = cacheService.getSysConfig(SysConfigKey.DEPOSIT_POST_NOTIFY_URL) url.split(",").forEach { val res = restTemplate.postForObject(it, enMsg, JsonNode::class.java) - val code = res["code"].toString() - if (code != "200") throw BizException(ErrorCode.UPLOAD_FAILURE) + val code = res?.get("code")?.asInt() ?: -1 + if (code != 200) throw BizException(ErrorCode.UPLOAD_FAILURE) } } - @Autowired lateinit var amqpTemplate: AmqpTemplate @@ -47,8 +47,4 @@ class PushComponent : LogService() { @Autowired lateinit var cacheService: com.wallet.biz.cache.CacheService - - val obj = ObjectMapper() - } - diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/request/HsmRequest.kt b/wallet-common/src/main/kotlin/com/wallet/biz/request/HsmRequest.kt index fb48353..c46c582 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/request/HsmRequest.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/request/HsmRequest.kt @@ -10,6 +10,7 @@ import com.wallet.biz.domain.vo.AddressVo import com.fasterxml.jackson.databind.ObjectMapper import org.consenlabs.tokencore.wallet.transaction.BitcoinTransaction import org.consenlabs.tokencore.wallet.transaction.TxSignResult +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.core.ParameterizedTypeReference import org.springframework.http.HttpEntity @@ -26,7 +27,9 @@ import java.util.* @Component class HsmRequest { - private fun getHsmUrl():String { + private val logger = LoggerFactory.getLogger(HsmRequest::class.java) + + private fun getHsmUrl(): String { return cacheService.getSysConfig(SysConfigKey.HSM_URL) } @@ -183,18 +186,20 @@ class HsmRequest { } private fun exchange(url: String, method: HttpMethod, body: Any?, responseClass: Class): T { - val response =try{ - restTemplate.exchange( + val response = try { + restTemplate.exchange( url, method, packRequest(body), object : ParameterizedTypeReference>() {} ).body - }catch (e:Exception){ + } catch (e: Exception) { + logger.error("HSM connection failed for $url: ${e.message}", e) throw BizException(ErrorCode.HSM_CONNECT_FAILURE) } + if (response == null) throw BizException(ErrorCode.HSM_CONNECT_FAILURE) if (response.code != 200) throw BizException(response.code, response.msg) - return obj.readValue(obj.writeValueAsString(response.data?:""), responseClass) + return obj.readValue(obj.writeValueAsString(response.data ?: ""), responseClass) } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/rpc/EosRpc.kt b/wallet-common/src/main/kotlin/com/wallet/biz/rpc/EosRpc.kt index 039c4bf..53bfe6f 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/rpc/EosRpc.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/rpc/EosRpc.kt @@ -1,10 +1,6 @@ package com.wallet.biz.rpc -import io.eblock.eos4j.Rpc - -/**
 - * Created by pie on 2019-03-20 18: 02.
 +/** + * EOS RPC client - reserved for future EOS chain support. */ -class EosRpc{ - -} +class EosRpc diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/rpc/RpcClient.kt b/wallet-common/src/main/kotlin/com/wallet/biz/rpc/RpcClient.kt index 1c765b2..97e9ccb 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/rpc/RpcClient.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/rpc/RpcClient.kt @@ -1,39 +1,46 @@ package com.wallet.biz.rpc import com.wallet.biz.dict.SysConfigKey -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Component import com.wallet.biz.rpc.BitcoinFork.* import com.fasterxml.jackson.databind.JsonNode -import com.wallet.biz.service.ConfigService +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate import wf.bitcoin.javabitcoindrpcclient.BitcoinJSONRPCClient import java.math.BigInteger -/**
 - * Created by pie on 2019-04-14 10: 32.
 - */ @Component class RpcClient { - var DEFAULT_GAS_PRICE = 90 + private val logger = LoggerFactory.getLogger(RpcClient::class.java) - var DEFAULT_SAT_PER_BYTE = 35L + @Volatile + private var lastGasPrice = 90 + + @Volatile + private var lastSatPerByte = 35L fun getGasPrice(): Int { return try { - val rpc=ethRpc() + val rpc = ethRpc() val gasPrice = rpc.ethGasPrice().send().gasPrice.divide(BigInteger.TEN.pow(9)).toInt() + lastGasPrice = gasPrice gasPrice } catch (e: Exception) { - val gasLevel = cacheService.getSysConfig(SysConfigKey.ETH_GAS_LEVEL) - val gasProp = cacheService.getSysConfig(SysConfigKey.GAS_PROP).toBigDecimal() - - val node = - restTemplate.getForObject("https://ethgasstation.info/json/ethgasAPI.json", JsonNode::class.java) - val gasPrice = (node[gasLevel].decimalValue() * gasProp).toInt() / 10 - DEFAULT_GAS_PRICE = gasPrice - gasPrice + logger.warn("Failed to get gas price from node, falling back to external API: ${e.message}") + try { + val gasLevel = cacheService.getSysConfig(SysConfigKey.ETH_GAS_LEVEL) + val gasProp = cacheService.getSysConfig(SysConfigKey.GAS_PROP).toBigDecimal() + val node = + restTemplate.getForObject("https://ethgasstation.info/json/ethgasAPI.json", JsonNode::class.java) + val gasPrice = (node!![gasLevel].decimalValue() * gasProp).toInt() / 10 + lastGasPrice = gasPrice + gasPrice + } catch (e2: Exception) { + logger.warn("Failed to get gas price from external API, using cached value: $lastGasPrice") + lastGasPrice + } } } @@ -42,14 +49,15 @@ class RpcClient { val gasLevel = cacheService.getSysConfig(SysConfigKey.BTC_GAS_LEVEL) val gasProp = cacheService.getSysConfig(SysConfigKey.GAS_PROP).toBigDecimal() val node = restTemplate.getForObject( - "https://bitcoinfees.earn.com/api/v1/fees/recommended", - JsonNode::class.java + "https://bitcoinfees.earn.com/api/v1/fees/recommended", + JsonNode::class.java ) - val satPetByte = (node[gasLevel].decimalValue() * gasProp).toLong() - DEFAULT_SAT_PER_BYTE = satPetByte - satPetByte + val satPerByte = (node!![gasLevel].decimalValue() * gasProp).toLong() + lastSatPerByte = satPerByte + satPerByte } catch (e: Exception) { - DEFAULT_SAT_PER_BYTE + logger.warn("Failed to get BTC fee estimate, using cached value: $lastSatPerByte") + lastSatPerByte } } @@ -90,30 +98,22 @@ class RpcClient { private fun getBTCOrForkRpcUrl(key: SysConfigKey): String { val url = cacheService.getSysConfig(key) - val rpc = BitcoinJSONRPCClient(url) - return try { - rpc.blockChainInfo - url - } catch (e: Exception) { - "http://127.0.0.1:8332" + if (url.isBlank()) { + logger.error("RPC URL not configured for $key") + throw IllegalStateException("RPC URL not configured for $key") } + return url } private fun getETHRpcUrl(): String { val url = cacheService.getSysConfig(SysConfigKey.ETH_RPC_URL) - val rpc=EthRpc(url) - return try { - rpc.ethBlockNumber() - url - } catch (e: Exception) { - return "http://127.0.0.1:8545" + if (url.isBlank()) { + logger.error("ETH RPC URL not configured") + throw IllegalStateException("ETH RPC URL not configured") } + return url } -// fun eosRpc(): EosApiRestClient { -// return EosApiClientFactory.newInstance(SysConfigKey.DOGE_RPC_URL.defaultValue).newRestClient() -// } - fun trxApi(): TrxApi { val url = cacheService.getSysConfig(SysConfigKey.TRX_API_URL) return TrxApi(url, restTemplate) @@ -122,10 +122,6 @@ class RpcClient { @Autowired lateinit var cacheService: com.wallet.biz.cache.CacheService - @Autowired - lateinit var configService: ConfigService - @Autowired lateinit var restTemplate: RestTemplate - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/rpc/TrxApi.kt b/wallet-common/src/main/kotlin/com/wallet/biz/rpc/TrxApi.kt index 0aa35ba..bf59f2b 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/rpc/TrxApi.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/rpc/TrxApi.kt @@ -6,31 +6,23 @@ import com.wallet.biz.utils.BasicUtils import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import org.consenlabs.tokencore.foundation.utils.NumericUtil +import org.slf4j.LoggerFactory import org.springframework.web.client.RestTemplate -import org.tron.trident.core.ApiWrapper -import java.lang.Exception - -/**
 - * Created by pie on 2020/9/7 18: 01.
 - */ class TrxApi(val url: String, val restTemplate: RestTemplate) { - val tronClient=ApiWrapper.ofMainnet("") + private val logger = LoggerFactory.getLogger(TrxApi::class.java) val callAddress = "TM1zzNDZD2DPASbKcgdVoTYhfmYgtfwx9R" - val sendTxUrl="http://13.127.47.162:8090" - fun easyTransferByPrivate( privateKey: String, fromAddress: String, toAddress: String, amount: Long ): JsonNode { - val res = createTransaction(toAddress, fromAddress, amount) - val signedTransaction = getTransactionSign(res, privateKey) + val signedTransaction = signTransactionLocally(res, privateKey) return broadcastTransaction(signedTransaction) } @@ -43,7 +35,7 @@ class TrxApi(val url: String, val restTemplate: RestTemplate) { feeLimit: Long ): JsonNode { val res = contractTransfer(contractAddress, fromAddress, toAddress, amount, feeLimit) - val signedTransaction = getTransactionSign(res["transaction"], privateKey) + val signedTransaction = signTransactionLocally(res["transaction"], privateKey) return broadcastTransaction(signedTransaction) } @@ -51,13 +43,54 @@ class TrxApi(val url: String, val restTemplate: RestTemplate) { return post("$url/wallet/broadcasttransaction", signedTransaction) } - fun getTransactionSign(transaction: JsonNode, privateKey: String): JsonNode { - val json=obj.writeValueAsString(transaction) - val map = hashMapOf( - "transaction" to json, - "privateKey" to privateKey - ) - return post("$sendTxUrl/wallet/gettransactionsign", map) + /** + * Local offline signing using ECDSA secp256k1 - private key never leaves the process. + * This replaces the old approach of sending private keys to a remote HTTP endpoint. + */ + private fun signTransactionLocally(transaction: JsonNode, privateKey: String): JsonNode { + val txId = transaction["txID"]?.asText() + ?: throw BizException(-1, "Transaction has no txID field") + val rawDataHex = transaction["raw_data_hex"]?.asText() + ?: throw BizException(-1, "Transaction has no raw_data_hex field") + + val txIdBytes = NumericUtil.hexToBytes(txId) + val privKeyBytes = NumericUtil.hexToBytes(privateKey) + + val ecKey = org.bitcoinj.core.ECKey.fromPrivate(privKeyBytes, false) + val signature = ecKey.sign(org.bitcoinj.core.Sha256Hash.wrap(txIdBytes)) + + val sigBytes = ByteArray(65) + val rBytes = signature.r.toByteArray() + val sBytes = signature.s.toByteArray() + System.arraycopy(rBytes, Math.max(0, rBytes.size - 32), sigBytes, Math.max(0, 32 - rBytes.size), Math.min(32, rBytes.size)) + System.arraycopy(sBytes, Math.max(0, sBytes.size - 32), sigBytes, Math.max(0, 64 - sBytes.size), Math.min(32, sBytes.size)) + sigBytes[64] = ecKey.findRecoveryId(org.bitcoinj.core.Sha256Hash.wrap(txIdBytes), signature).toByte() + + val signatureHex = NumericUtil.bytesToHex(sigBytes) + + val signedTx = obj.createObjectNode() + signedTx.set("raw_data", transaction["raw_data"]) + signedTx.put("raw_data_hex", rawDataHex) + signedTx.put("txID", txId) + val sigArray = signedTx.putArray("signature") + sigArray.add(signatureHex) + + return signedTx + } + + fun easyTransferByPrivate(privateKey: String, toAddress: String, amount: Long): JsonNode { + val fromAddress = getAddressFromPrivateKey(privateKey) + return easyTransferByPrivate(privateKey, fromAddress, toAddress, amount) + } + + private fun getAddressFromPrivateKey(privateKey: String): String { + val ecKey = org.bitcoinj.core.ECKey.fromPrivate(NumericUtil.hexToBytes(privateKey), false) + val pubKeyBytes = ecKey.pubKeyPoint.getEncoded(false) + val addressBytes = ByteArray(21) + addressBytes[0] = 0x41 + val hash = org.web3j.crypto.Hash.sha3(pubKeyBytes.copyOfRange(1, pubKeyBytes.size)) + System.arraycopy(hash, 12, addressBytes, 1, 20) + return BasicUtils.encode58Check(addressBytes) } fun accounts(address: String): JsonNode { @@ -99,30 +132,6 @@ class TrxApi(val url: String, val restTemplate: RestTemplate) { return get("$url/wallet/getnowblock") } - fun easyTransferByPrivate(privateKey: String, toAddress: String, amount: Long): JsonNode { - val map = hashMapOf( - "privateKey" to privateKey, - "toAddress" to toAddress, - "amount" to amount, - "visible" to true - ) - val node = post("$sendTxUrl/wallet/easytransferbyprivate", map) - if (node["result"]["code"] != null) throw BizException(-1, node["result"]["message"].textValue()) - return node - } - - fun easyTransferAssetByPrivate(privateKey: String, toAddress: String, assetId: String, amount: Long): JsonNode { - val map = hashMapOf( - "privateKey" to privateKey, - "toAddress" to toAddress, - "assetId" to assetId, - "amount" to amount, - "visible" to true - ) - return post("$sendTxUrl/wallet/easytransferassetbyprivate", map) - } - - fun createTransaction(toAddress: String, ownerAddress: String, amount: Long): JsonNode { val map = hashMapOf("to_address" to toAddress, "owner_address" to ownerAddress, "amount" to amount, "visible" to true) @@ -199,17 +208,16 @@ class TrxApi(val url: String, val restTemplate: RestTemplate) { } private fun post(url: String, body: Any): JsonNode { - return restTemplate.postForObject(url, obj.writeValueAsString(body), JsonNode::class.java) + return restTemplate.postForObject(url, obj.writeValueAsString(body), JsonNode::class.java)!! } private fun get(url: String): JsonNode { - return restTemplate.getForObject(url, JsonNode::class.java) + return restTemplate.getForObject(url, JsonNode::class.java)!! } fun getTransactionInfo(txid: String): JsonNode { return get("https://apilist.tronscan.org/api/transaction-info?hash=$txid") } - private val obj = ObjectMapper() } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/utils/BasicUtils.kt b/wallet-common/src/main/kotlin/com/wallet/biz/utils/BasicUtils.kt index 9d0d5c6..d5fdf3d 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/utils/BasicUtils.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/utils/BasicUtils.kt @@ -3,50 +3,40 @@ package com.wallet.biz.utils import org.apache.commons.lang3.StringUtils import org.bitcoinj.core.Base58 import org.consenlabs.tokencore.foundation.utils.NumericUtil +import org.slf4j.LoggerFactory import org.springframework.beans.BeanUtils -import org.web3j.crypto.Hash -import java.util.HashSet - -import org.springframework.beans.BeanWrapperImpl - import org.springframework.beans.BeanWrapper +import org.springframework.beans.BeanWrapperImpl +import org.web3j.crypto.Hash - - - -/**
 - * Created by pie on 2020/9/7 19: 24.
 - */ class BasicUtils { - companion object{ + companion object { + private val logger = LoggerFactory.getLogger(BasicUtils::class.java) - fun copyPropertiesIgnoreNull(source:Any,target:Any){ - BeanUtils.copyProperties(source,target,*getNullPropertyNames(source)) + fun copyPropertiesIgnoreNull(source: Any, target: Any) { + BeanUtils.copyProperties(source, target, *getNullPropertyNames(source)) } fun getNullPropertyNames(source: Any): Array { val src: BeanWrapper = BeanWrapperImpl(source) val pds = src.propertyDescriptors - val emptyNames= HashSet() + val emptyNames = HashSet() for (pd in pds) { - //check if value of this property is null then add it to the collection val srcValue = src.getPropertyValue(pd.name) if (srcValue == null) { emptyNames.add(pd.name) } } - val result = arrayOfNulls(emptyNames.size) - return emptyNames.toArray(result) + return emptyNames.toTypedArray() } - - fun base58CheckToHexString(input: String):String{ - val byteArray=decode58Check(input) + fun base58CheckToHexString(input: String): String { + val byteArray = decode58Check(input) return NumericUtil.bytesToHex(byteArray) } - fun hexToBase58(input: String):String{ - val byteArray=NumericUtil.hexToBytes(input) + fun hexToBase58(input: String): String { + val byteArray = NumericUtil.hexToBytes(input) return encode58Check(byteArray) } @@ -68,7 +58,10 @@ class BasicUtils { System.arraycopy(decodeCheck, 0, decodeData, 0, decodeData.size) val hash0: ByteArray = Hash.sha256(decodeData) val hash1: ByteArray = Hash.sha256(hash0) - return if (hash1[0] == decodeCheck[decodeData.size] && hash1[1] == decodeCheck[decodeData.size + 1] && hash1[2] == decodeCheck[decodeData.size + 2] && hash1[3] == decodeCheck[decodeData.size + 3] + return if (hash1[0] == decodeCheck[decodeData.size] + && hash1[1] == decodeCheck[decodeData.size + 1] + && hash1[2] == decodeCheck[decodeData.size + 2] + && hash1[3] == decodeCheck[decodeData.size + 3] ) { decodeData } else null @@ -76,11 +69,10 @@ class BasicUtils { fun decodeFromBase58Check(addressBase58: String): ByteArray? { if (StringUtils.isEmpty(addressBase58)) { - println("Warning: Address is empty !!") + logger.warn("Address is empty") return null } - return decode58Check(addressBase58) + return decode58Check(addressBase58) } } - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/utils/Crypto.kt b/wallet-common/src/main/kotlin/com/wallet/biz/utils/Crypto.kt index 2f28f81..c32fb77 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/utils/Crypto.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/utils/Crypto.kt @@ -1,32 +1,64 @@ package com.wallet.biz.utils +import java.security.SecureRandom import java.util.Base64 import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec -object Crypto{ - @JvmStatic fun aesEncrypt(v:String, secretKey:String) = AES256.encrypt(v, secretKey) - @JvmStatic fun aesDecrypt(v:String, secretKey:String) = AES256.decrypt(v, secretKey) +object Crypto { + @JvmStatic + fun aesEncrypt(v: String, secretKey: String) = AES256.encrypt(v, secretKey) + + @JvmStatic + fun aesDecrypt(v: String, secretKey: String) = AES256.decrypt(v, secretKey) } -private object AES256{ - private val encorder = Base64.getEncoder() - private val decorder = Base64.getDecoder() - private fun cipher(opmode:Int, secretKey:String):Cipher{ - if(secretKey.length != 32) throw RuntimeException("SecretKey length is not 32 chars") - val c = Cipher.getInstance("AES/CBC/PKCS5Padding") - val sk = SecretKeySpec(secretKey.toByteArray(Charsets.UTF_8), "AES") - val iv = IvParameterSpec(secretKey.substring(0, 16).toByteArray(Charsets.UTF_8)) - c.init(opmode, sk, iv) - return c +private object AES256 { + private val encoder = Base64.getEncoder() + private val decoder = Base64.getDecoder() + private val secureRandom = SecureRandom() + + private fun getKeySpec(secretKey: String): SecretKeySpec { + if (secretKey.length != 32) throw RuntimeException("SecretKey length is not 32 chars") + return SecretKeySpec(secretKey.toByteArray(Charsets.UTF_8), "AES") } - fun encrypt(str:String, secretKey:String):String{ - val encrypted = cipher(Cipher.ENCRYPT_MODE, secretKey).doFinal(str.toByteArray(Charsets.UTF_8)) - return String(encorder.encode(encrypted)) + + fun encrypt(str: String, secretKey: String): String { + val iv = ByteArray(16) + secureRandom.nextBytes(iv) + val ivSpec = IvParameterSpec(iv) + val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") + cipher.init(Cipher.ENCRYPT_MODE, getKeySpec(secretKey), ivSpec) + val encrypted = cipher.doFinal(str.toByteArray(Charsets.UTF_8)) + val combined = ByteArray(iv.size + encrypted.size) + System.arraycopy(iv, 0, combined, 0, iv.size) + System.arraycopy(encrypted, 0, combined, iv.size, encrypted.size) + return String(encoder.encode(combined)) } - fun decrypt(str:String, secretKey:String):String{ - val byteStr = decorder.decode(str.toByteArray(Charsets.UTF_8)) - return String(cipher(Cipher.DECRYPT_MODE, secretKey).doFinal(byteStr)) + + fun decrypt(str: String, secretKey: String): String { + val combined = decoder.decode(str.toByteArray(Charsets.UTF_8)) + if (combined.size < 16) { + return decryptLegacy(str, secretKey) + } + return try { + val iv = combined.copyOfRange(0, 16) + val encrypted = combined.copyOfRange(16, combined.size) + val ivSpec = IvParameterSpec(iv) + val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") + cipher.init(Cipher.DECRYPT_MODE, getKeySpec(secretKey), ivSpec) + String(cipher.doFinal(encrypted)) + } catch (e: Exception) { + decryptLegacy(str, secretKey) + } } -} \ No newline at end of file + + private fun decryptLegacy(str: String, secretKey: String): String { + val byteStr = decoder.decode(str.toByteArray(Charsets.UTF_8)) + val iv = IvParameterSpec(secretKey.substring(0, 16).toByteArray(Charsets.UTF_8)) + val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") + cipher.init(Cipher.DECRYPT_MODE, getKeySpec(secretKey), iv) + return String(cipher.doFinal(byteStr)) + } +} diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/utils/ETHUtils.kt b/wallet-common/src/main/kotlin/com/wallet/biz/utils/ETHUtils.kt index 721a71f..1160d8a 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/utils/ETHUtils.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/utils/ETHUtils.kt @@ -13,30 +13,33 @@ import org.web3j.abi.datatypes.Type import org.web3j.abi.datatypes.generated.Uint256 import org.web3j.protocol.core.DefaultBlockParameterName import org.web3j.protocol.core.methods.request.Transaction -import java.lang.Exception import java.math.BigDecimal import java.math.BigInteger -/**
 - * Created by pie on 2020/7/9 20: 02.
 - */ @Component class ETHUtils { - private fun createContractData(functionName: String, params: List>): String { + private fun createTransferFunctionData(functionName: String, params: List>): String { val function = Function( functionName, params, - listOf>(object : TypeReference() { + listOf>(object : TypeReference() {}) + ) + return FunctionEncoder.encode(function) + } - }) + private fun createViewFunctionData(functionName: String, params: List>): String { + val function = Function( + functionName, + params, + listOf>(object : TypeReference() {}) ) return FunctionEncoder.encode(function) } private fun ethCall(functionName: String, contractAddress: String, params: List>): String { val rpc = rpcClient.ethRpc() - val data = createContractData(functionName, params) + val data = createViewFunctionData(functionName, params) return rpc.handleError( rpc.ethCall( Transaction.createEthCallTransaction(contractAddress, contractAddress, data), @@ -45,15 +48,15 @@ class ETHUtils { ).value } - fun estimateContractGasWithMaxBalance(from: String, to: String,tokenAddress:String):Long{ - val tokenBalance=getContractBalance(tokenAddress,from) - return estimateContractGas(from,to,tokenBalance,tokenAddress) + fun estimateContractGasWithMaxBalance(from: String, to: String, tokenAddress: String): Long { + val tokenBalance = getContractBalance(tokenAddress, from) + return estimateContractGas(from, to, tokenBalance, tokenAddress) } - fun estimateContractGas(from: String, to: String,amount: BigDecimal,tokenAddress:String):Long{ + fun estimateContractGas(from: String, to: String, amount: BigDecimal, tokenAddress: String): Long { val decimals = getETHContractDecimals(tokenAddress) - val data=createContractTransferData(amount,to,decimals) - return estimateGas(from,tokenAddress,data) + val data = createContractTransferData(amount, to, decimals) + return estimateGas(from, tokenAddress, data) } fun estimateGas(from: String, to: String, data: String): Long { @@ -65,41 +68,42 @@ class ETHUtils { fun getETHContractDecimals(contractAddress: String): Int { val value = ethCall("decimals", contractAddress, listOf()) - if (value == "0x") return 0 - return value.replaceFirst("0x", "").toInt(16) + if (value == "0x" || value.isNullOrBlank()) return 0 + return try { + value.removePrefix("0x").toBigInteger(16).toInt() + } catch (e: NumberFormatException) { + 0 + } } fun getEthContractBalanceNoDivide(contractAddress: String, address: String): BigDecimal { val value = ethCall("balanceOf", contractAddress, listOf(Address(address))) - if (value == "0x") return BigDecimal.ZERO + if (value == "0x" || value.isNullOrBlank()) return BigDecimal.ZERO return BigDecimal(BigInteger(value.replace("0x", ""), 16).toString()) } fun getContractBalance(contractAddress: String, address: String): BigDecimal { val amount = getEthContractBalanceNoDivide(contractAddress, address) val decimals = getETHContractDecimals(contractAddress) + if (decimals == 0) return amount return amount.divide(BigDecimal.TEN.pow(decimals)) } fun getBalance(address: String): BigDecimal { val rpc = rpcClient.ethRpc() return rpc.handleError( - rpc.ethGetBalance( - address, - DefaultBlockParameterName.PENDING - ).send() - ).balance.toBigDecimal().divide( - BigDecimal.TEN.pow(18) - ) + rpc.ethGetBalance(address, DefaultBlockParameterName.PENDING).send() + ).balance.toBigDecimal().divide(BigDecimal.TEN.pow(18)) } - fun decodeTransferInput(inputData: String): DecodedTransferInput { val i = DecodedTransferInput() try { i.methodID = inputData.substring(0, 10) - i.to = hexToAddress(inputData.substring(10, 74)) - i.value = hexToBigInteger(inputData.substring(74)) + val rawHex = inputData.substring(10, 74).removePrefix("0x").removePrefix("0X") + i.to = "0x${rawHex.substring(24)}" + val valueHex = inputData.substring(74).removePrefix("0x").removePrefix("0X") + i.value = BigInteger(valueHex, 16) i.pass = true } catch (e: Exception) { i.pass = false @@ -107,55 +111,15 @@ class ETHUtils { return i } - /** - *

功能描述:16进制转10进制整数。

- *

jl

- * @param strHex - * @since JDK1.8 - *

创建日期:2018/10/19 15:55。

- *

更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。

- */ - private fun hexToBigInteger(hex: String): BigInteger? { - var strHex = hex - if (strHex.length > 2) { - if (strHex[0] == '0' && (strHex[1] == 'X' || strHex[1] == 'x')) { - strHex = strHex.substring(2); - } - val bigInteger = BigInteger(strHex, 16); - return bigInteger; - } - return null; - } - - /** - *

功能描述:hex地址转地址。

- *

jl

- * @param strHex - * @since JDK1.8 - *

创建日期:2018/10/19 16:24。

- *

更新日期:[日期YYYY-MM-DD][更改人姓名][变更描述]。

- */ - private fun hexToAddress(hex: String): String? { - var strHex = hex - if (strHex.length > 42) { - if (strHex[0] == '0' && (strHex[1] == 'X' || strHex[1] == 'x')) { - strHex = strHex.substring(2); - } - strHex = strHex.substring(24); - return "0x$strHex"; - } - return null; - } - fun createContractTransferData(amount: BigDecimal, to: String, decimals: Int): String { - return createContractData("transfer",listOf( - Address(to), - Uint256(amount.multiply(BigDecimal.TEN.pow(decimals)).toBigInteger()) - )) + return createTransferFunctionData( + "transfer", listOf( + Address(to), + Uint256(amount.multiply(BigDecimal.TEN.pow(decimals)).toBigInteger()) + ) + ) } - @Autowired lateinit var rpcClient: RpcClient - } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/utils/OMNIUtils.kt b/wallet-common/src/main/kotlin/com/wallet/biz/utils/OMNIUtils.kt index d82a291..05c63a8 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/utils/OMNIUtils.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/utils/OMNIUtils.kt @@ -1,30 +1,21 @@ package com.wallet.biz.utils -import com.wallet.biz.domain.ApiDomain import com.wallet.biz.domain.dict.ErrorCode import com.wallet.biz.domain.exception.BizException import com.wallet.biz.rpc.RpcClient import com.wallet.biz.xservice.WalletXService -import com.fasterxml.jackson.databind.ObjectMapper import org.consenlabs.tokencore.wallet.model.ChainType -import org.consenlabs.tokencore.wallet.model.TokenException -import org.consenlabs.tokencore.wallet.transaction.BitcoinTransaction import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component -import org.springframework.web.client.RestTemplate import java.math.BigDecimal -import java.util.ArrayList -/**
 - * Created by pie on 2020/7/11 16: 15.
 - */ @Component class OMNIUtils { - fun getOMNIBalance(address: String, propertyId: String): BigDecimal { val rpc = rpcClient.omniRpc() - return rpc.omniGetBalance(address, propertyId).balance ?: throw BizException(ErrorCode.API_NETWORK_BUSY) + return rpc.omniGetBalance(address, propertyId).balance + ?: throw BizException(ErrorCode.API_NETWORK_BUSY) } fun getBTCBalance(address: String): BigDecimal { @@ -37,15 +28,9 @@ class OMNIUtils { } fun calculateFee(inputNum: Int, outputNum: Int, satPerByte: Long): Long { - return (148 * inputNum + 34 * outputNum + 10) * satPerByte + return (148L * inputNum + 34L * outputNum + 10L) * satPerByte } - - @Autowired - lateinit var rpcClient: RpcClient - @Autowired - lateinit var restTemplate: RestTemplate - @Autowired - lateinit var walletXService: WalletXService - val obj=ObjectMapper() + @Autowired lateinit var rpcClient: RpcClient + @Autowired lateinit var walletXService: WalletXService } diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/AdminXServiceImpl.kt b/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/AdminXServiceImpl.kt index b7e708c..f7fde9a 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/AdminXServiceImpl.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/AdminXServiceImpl.kt @@ -8,9 +8,6 @@ import org.apache.commons.codec.digest.Md5Crypt import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service -/**
 - * Created by pie on 2020/12/7 13: 06.
 - */ @Service class AdminXServiceImpl : AdminXService { @@ -25,7 +22,6 @@ class AdminXServiceImpl : AdminXService { override fun login(name: String, password: String): String { val user = userService.getByName(name) ?: throw BizException(-1, "用户名密码错误") val enPass = Md5Crypt.md5Crypt(password.toByteArray(), user.salt, "") - if (user.password != enPass) throw BizException(-1, "用户名密码错误") return user.accessToken } @@ -50,30 +46,30 @@ class AdminXServiceImpl : AdminXService { return blockHeightService.findAll() } - override fun getTokenList(): List { return walletTokenService.findAll() } override fun getDashboard(): Map { - val totalAddress = addressService.findAll().size - val deL = depositService.findAll() - val totalDeposit = deL.size - val totalWithdraw = withdrawService.findAll().size - val totalTx = totalDeposit + totalWithdraw - val pieGroup = deL.groupBy { it.chainType } - val pieLabels = pieGroup.keys - val pieData = pieGroup.values.map { it.size } - val pieChart = mapOf("labels" to pieLabels, "data" to pieData) - val areaGroup=deL.groupBy { "${it.createdAt.year}-${it.createdAt.month}" } - val areaLabels=areaGroup.keys - val areaData=areaGroup.values.map { it.size } - val areaChart = mapOf("labels" to areaLabels, "data" to areaData) + val addressCount = addressService.findAll().size + val deposits = depositService.findAll() + val depositCount = deposits.size + val withdrawCount = withdrawService.findAll().size + val totalTx = depositCount + withdrawCount + + val pieGroup = deposits.groupBy { it.chainType ?: "UNKNOWN" } + val pieChart = mapOf("labels" to pieGroup.keys.toList(), "data" to pieGroup.values.map { it.size }) + + val areaGroup = deposits.groupBy { + val date = it.createdAt + if (date != null) "${date.year + 1900}-${date.month + 1}" else "unknown" + } + val areaChart = mapOf("labels" to areaGroup.keys.toList(), "data" to areaGroup.values.map { it.size }) return mapOf( - "totalAddress" to totalAddress, - "totalDeposit" to totalDeposit, - "totalWithdraw" to totalWithdraw, + "totalAddress" to addressCount, + "totalDeposit" to depositCount, + "totalWithdraw" to withdrawCount, "totalTx" to totalTx, "pieChart" to pieChart, "areaChart" to areaChart @@ -81,18 +77,18 @@ class AdminXServiceImpl : AdminXService { } override fun addAddrAdmin(type: Int, address: String, chainType: String) { - val addrAdmin= AddressAdmin() - if(type!=200){ - val find= Address() - find.address=address - val wAddr=addressService.findByBean(find).firstOrNull()?:throw BizException(-1,"添加热钱包或者gas钱包必须是在本钱包有生成过的地址") - addrAdmin.walletCode=wAddr.walletCode + val addrAdmin = AddressAdmin() + if (type != 200) { + val find = Address() + find.address = address + val wAddr = addressService.findByBean(find).firstOrNull() + ?: throw BizException(-1, "添加热钱包或者gas钱包必须是在本钱包有生成过的地址") + addrAdmin.walletCode = wAddr.walletCode addressService.delete(wAddr.id) } - addrAdmin.address=address - addrAdmin.addressType=type - addrAdmin.chainType=chainType - + addrAdmin.address = address + addrAdmin.addressType = type + addrAdmin.chainType = chainType addressAdminService.save(addrAdmin) } @@ -136,32 +132,14 @@ class AdminXServiceImpl : AdminXService { whiteService.del(id) } - @Autowired - lateinit var addressAdminService: AddressAdminService - @Autowired - lateinit var depositService: DepositService - @Autowired - lateinit var withdrawService: WithdrawService - @Autowired - lateinit var blockHeightService: BlockHeightService - @Autowired - lateinit var walletTokenService: TokenService - @Autowired - lateinit var addressService: AddressService - @Autowired - lateinit var configService: ConfigService - @Autowired - lateinit var userService: UserService - @Autowired - lateinit var cacheService: com.wallet.biz.cache.CacheService - @Autowired - lateinit var whiteService: WhiteService + @Autowired lateinit var addressAdminService: AddressAdminService + @Autowired lateinit var depositService: DepositService + @Autowired lateinit var withdrawService: WithdrawService + @Autowired lateinit var blockHeightService: BlockHeightService + @Autowired lateinit var walletTokenService: TokenService + @Autowired lateinit var addressService: AddressService + @Autowired lateinit var configService: ConfigService + @Autowired lateinit var userService: UserService + @Autowired lateinit var cacheService: com.wallet.biz.cache.CacheService + @Autowired lateinit var whiteService: WhiteService } - -fun main() { - - val a=Md5Crypt.md5Crypt("v423hgv".toByteArray(), "32134", "") - - print(a) -} - diff --git a/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/WalletXServiceImpl.kt b/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/WalletXServiceImpl.kt index 5a8b5d3..62f8848 100644 --- a/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/WalletXServiceImpl.kt +++ b/wallet-common/src/main/kotlin/com/wallet/biz/xservice/impl/WalletXServiceImpl.kt @@ -441,7 +441,7 @@ open class WalletXServiceImpl : WalletXService, LogService() { val signedTx = rpc.signRawTransaction(unsignedTx, null, listOf(wifiKey)) rpc.sendRawTransaction(signedTx) } catch (e: Exception) { - log("${ChainType.BITCOINCASH}转币失败,失败原因:${e.message}") + log("${chainType}转币失败,失败原因:${e.message}") throw e } saveWithReocord( @@ -450,10 +450,10 @@ open class WalletXServiceImpl : WalletXService, LogService() { sendPo.to!!, sendAddr, WithType.SEND, - ChainType.BITCOINCASH, + chainType, "" ) - log("${ChainType.BITCOINCASH}转币成功 保存转币记录到数据库") + log("${chainType}转币成功 保存转币记录到数据库") return txid } @@ -899,9 +899,7 @@ open class WalletXServiceImpl : WalletXService, LogService() { Address(toAddress), Uint256(amount.multiply(BigDecimal.TEN.pow(decimals)).toBigInteger()) ), - listOf>(object : TypeReference() { - - }) + listOf>(object : TypeReference() {}) ) return FunctionEncoder.encode(function) } @@ -910,9 +908,7 @@ open class WalletXServiceImpl : WalletXService, LogService() { val function = Function( "balanceOf", listOf(Address(address)), - listOf>(object : TypeReference() { - - }) + listOf>(object : TypeReference() {}) ) return FunctionEncoder.encode(function) } diff --git a/wallet-entity/build.gradle b/wallet-entity/build.gradle index d391450..d3e7a03 100644 --- a/wallet-entity/build.gradle +++ b/wallet-entity/build.gradle @@ -1,37 +1,9 @@ -bootRepackage.enabled=false - -apply plugin: "com.waykichain.utils.codegen" +bootJar.enabled = false +jar.enabled = true dependencies { - - // // QueryDSL - compile "com.querydsl:querydsl-jpa:$querydslVersion" -// compile "com.querydsl:querydsl-auth:$querydslVersion" - compile "com.querydsl:querydsl-sql-spring:$querydslVersion" - compile "com.querydsl:querydsl-sql:$querydslVersion" - compile "com.querydsl:querydsl-core:$querydslVersion" -} - -buildscript { - repositories { - maven { url "https://plugins.gradle.org/m2/" } - } - - dependencies { - classpath "gradle.plugin.com.waykichain.utils.codegen:querydsl-plugin:1.2.27" - classpath 'mysql:mysql-connector-java:5.1.40' - } -} - -querydsl { - driverClass = 'com.mysql.jdbc.Driver' - userName = 'root' - password = '123456' - jdbcUrl = 'jdbc:mysql://127.0.0.1:3306/wallet_db?allowMultiQueries=true&useSSL=false&autoReconnect=true' - domainSrcPath = "$project.projectDir/src/main/java/" - domainPackageName = 'com.wallet.entity.domain' - repositorySrcPath = "$project.projectDir/src/main/kotlin/" - repositoryPackageName = 'com.wallet.repository' - serviceSrcPath = "$project.projectDir/../wallet-common/src/main/kotlin/" - servicePackageName = 'com.wallet.biz.service' + implementation "com.querydsl:querydsl-jpa:$querydslVersion:jakarta" + implementation "com.querydsl:querydsl-sql-spring:$querydslVersion" + implementation "com.querydsl:querydsl-sql:$querydslVersion" + implementation "com.querydsl:querydsl-core:$querydslVersion" } diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/Address.java b/wallet-entity/src/main/java/com/wallet/entity/domain/Address.java index 7158985..0973800 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/Address.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/Address.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -31,7 +31,7 @@ public class Address implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("memo") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/AddressAdmin.java b/wallet-entity/src/main/java/com/wallet/entity/domain/AddressAdmin.java index 0b4fdd6..3a3ce64 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/AddressAdmin.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/AddressAdmin.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -31,7 +31,7 @@ public class AddressAdmin implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("updated_at") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/BlockHeight.java b/wallet-entity/src/main/java/com/wallet/entity/domain/BlockHeight.java index ba14964..58b020f 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/BlockHeight.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/BlockHeight.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -28,7 +28,7 @@ public class BlockHeight implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("updated_at") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/Config.java b/wallet-entity/src/main/java/com/wallet/entity/domain/Config.java index e34421e..a2aff94 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/Config.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/Config.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -34,7 +34,7 @@ public class Config implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("updated_at") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/Deposit.java b/wallet-entity/src/main/java/com/wallet/entity/domain/Deposit.java index 5228432..1fd1532 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/Deposit.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/Deposit.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -40,7 +40,7 @@ public class Deposit implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("is_upload") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QAddress.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QAddress.java index fadc4b7..95959e5 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QAddress.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QAddress.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QAddressAdmin.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QAddressAdmin.java index 7078005..f633942 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QAddressAdmin.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QAddressAdmin.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QBlockHeight.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QBlockHeight.java index eb00a4b..bf52001 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QBlockHeight.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QBlockHeight.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QConfig.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QConfig.java index 8835eda..6046234 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QConfig.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QConfig.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QDeposit.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QDeposit.java index c9bb64a..c632946 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QDeposit.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QDeposit.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QToken.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QToken.java index 2ca2701..930bd01 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QToken.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QToken.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QUser.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QUser.java index 3a214d9..5305bee 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QUser.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QUser.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitCollect.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitCollect.java index 0631d95..52876a7 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitCollect.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitCollect.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitImport.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitImport.java index 503d0f3..5628203 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitImport.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QWaitImport.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QWhite.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QWhite.java index 13a6f28..f4d82c4 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QWhite.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QWhite.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/QWithdraw.java b/wallet-entity/src/main/java/com/wallet/entity/domain/QWithdraw.java index b39df58..aa6d5e2 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/QWithdraw.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/QWithdraw.java @@ -5,7 +5,7 @@ import com.querydsl.core.types.dsl.*; import com.querydsl.core.types.PathMetadata; -import javax.annotation.Generated; +import jakarta.annotation.Generated; import com.querydsl.core.types.Path; import com.querydsl.sql.ColumnMetadata; diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/Token.java b/wallet-entity/src/main/java/com/wallet/entity/domain/Token.java index 62d8941..95afd02 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/Token.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/Token.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -28,7 +28,7 @@ public class Token implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("min_collect") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/User.java b/wallet-entity/src/main/java/com/wallet/entity/domain/User.java index bbe29ee..c771141 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/User.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/User.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -25,7 +25,7 @@ public class User implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("name") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/WaitCollect.java b/wallet-entity/src/main/java/com/wallet/entity/domain/WaitCollect.java index 1e0302b..d908910 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/WaitCollect.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/WaitCollect.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -28,7 +28,7 @@ public class WaitCollect implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("send_fee") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/WaitImport.java b/wallet-entity/src/main/java/com/wallet/entity/domain/WaitImport.java index e8feb4c..9b26386 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/WaitImport.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/WaitImport.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -28,7 +28,7 @@ public class WaitImport implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("updated_at") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/White.java b/wallet-entity/src/main/java/com/wallet/entity/domain/White.java index 17cca9b..4115f2f 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/White.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/White.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -22,7 +22,7 @@ public class White implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("ip") diff --git a/wallet-entity/src/main/java/com/wallet/entity/domain/Withdraw.java b/wallet-entity/src/main/java/com/wallet/entity/domain/Withdraw.java index 5f6cd68..5d718b8 100644 --- a/wallet-entity/src/main/java/com/wallet/entity/domain/Withdraw.java +++ b/wallet-entity/src/main/java/com/wallet/entity/domain/Withdraw.java @@ -1,12 +1,12 @@ package com.wallet.entity.domain; -import javax.persistence.Entity; -import javax.annotation.Generated; -import javax.persistence.GeneratedValue; +import jakarta.persistence.Entity; +import jakarta.annotation.Generated; +import jakarta.persistence.GeneratedValue; import org.hibernate.annotations.DynamicUpdate; import com.querydsl.sql.Column; import org.hibernate.annotations.DynamicInsert; -import javax.persistence.Id; +import jakarta.persistence.Id; import java.io.Serializable; /** @@ -34,7 +34,7 @@ public class Withdraw implements Serializable { @Column("id") @Id - @GeneratedValue(strategy=javax.persistence.GenerationType.IDENTITY) + @GeneratedValue(strategy=jakarta.persistence.GenerationType.IDENTITY) private Long id; @Column("to_address") diff --git a/wallet-hsm/Dockerfile b/wallet-hsm/Dockerfile index ad1f9da..217899a 100644 --- a/wallet-hsm/Dockerfile +++ b/wallet-hsm/Dockerfile @@ -1,8 +1,25 @@ -FROM openjdk:8-jdk-alpine -VOLUME /tmp -VOLUME /etc/localtime:/etc/localtime -COPY build/libs/cl-hsm-0.0.1-SNAPSHOT.jar /mnt/cl-hsm-0.0.1-SNAPSHOT.jar -COPY src/main/resources/application.yml /mnt/application.yml -ENV PORT 10888 +# Stage 1: Build +FROM eclipse-temurin:17-jdk-alpine AS builder +WORKDIR /app +COPY . . +RUN chmod +x ./gradlew && ./gradlew :wallet-hsm:bootJar --no-daemon -x test + +# Stage 2: Runtime +FROM eclipse-temurin:17-jre-alpine +WORKDIR /app + +RUN addgroup -S wallet && adduser -S wallet -G wallet + +COPY --from=builder /app/wallet-hsm/build/libs/*.jar app.jar + +ENV PORT=10888 +ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" + EXPOSE $PORT -ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/mnt/cl-hsm-0.0.1-SNAPSHOT.jar"] \ No newline at end of file + +USER wallet + +HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT}/actuator/health || exit 1 + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dserver.port=${PORT} -jar app.jar"] diff --git a/wallet-hsm/build.gradle b/wallet-hsm/build.gradle index 610d95f..5c5514e 100644 --- a/wallet-hsm/build.gradle +++ b/wallet-hsm/build.gradle @@ -1,9 +1,25 @@ plugins { id 'com.google.cloud.tools.jib' version '3.4.0' } + apply plugin: 'application' +mainClassName = "com.wallet.HsmApplicationKt" + dependencies { - compile project(":wallet-entity") + implementation project(":wallet-entity") } +jib { + from { + image = 'eclipse-temurin:17-jre-alpine' + } + to { + image = "wallet-hsm:${project.version}" + } + container { + mainClass = 'com.wallet.HsmApplicationKt' + ports = ['10888'] + jvmFlags = ['-Xms256m', '-Xmx512m', '-Djava.security.egd=file:/dev/./urandom'] + } +} diff --git a/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/ScanKeyStoreConfig.kt b/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/ScanKeyStoreConfig.kt index 9305460..0b54b8d 100644 --- a/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/ScanKeyStoreConfig.kt +++ b/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/ScanKeyStoreConfig.kt @@ -12,7 +12,7 @@ import org.springframework.context.annotation.Configuration import java.io.File import java.nio.file.Files import java.nio.file.Paths -import javax.annotation.PostConstruct +import jakarta.annotation.PostConstruct /** * Created by pie on 2019/2/15 15: 36. diff --git a/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/globalhandler/GlobalHandler.kt b/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/globalhandler/GlobalHandler.kt index 46a1108..aa7730e 100644 --- a/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/globalhandler/GlobalHandler.kt +++ b/wallet-hsm/src/main/kotlin/com/wallet/hsm/config/globalhandler/GlobalHandler.kt @@ -2,37 +2,24 @@ package com.wallet.hsm.config.globalhandler import com.wallet.biz.domain.dict.TokenResponse import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice import wf.bitcoin.javabitcoindrpcclient.BitcoinRPCException -import javax.servlet.http.HttpServletRequest @RestControllerAdvice class GlobalHandler { + private val log = LoggerFactory.getLogger(GlobalHandler::class.java) + @ExceptionHandler(Exception::class) fun handleException(e: Exception): TokenResponse { - - val message = when (0) { - 0 -> e.message.toString() - else -> e.stackTrace.joinToString(" ") - } - val requestPath = request.requestURI + "?" + request.queryString - log.error(e.message) - return TokenResponse(-1, "$requestPath $message", "") + log.error("HSM unhandled exception: ${e.message}", e) + return TokenResponse(-1, e.message ?: "Internal server error", "") } @ExceptionHandler(BitcoinRPCException::class) fun handleBizException(e: BitcoinRPCException): TokenResponse { - log.error(e.message) - val requestPath = request.requestURI + "?" + request.queryString - return TokenResponse(e.rpcError.code, "$requestPath ${e.rpcError.message}", "") + log.error("HSM Bitcoin RPC exception: ${e.rpcError?.message}", e) + return TokenResponse(e.rpcError?.code ?: -1, e.rpcError?.message ?: "RPC error", "") } - - @Autowired - lateinit var request: HttpServletRequest - val log = LoggerFactory.getLogger(this.javaClass) - } diff --git a/wallet-hsm/src/main/kotlin/com/wallet/hsm/env/KeyStoreProperties.kt b/wallet-hsm/src/main/kotlin/com/wallet/hsm/env/KeyStoreProperties.kt index b08511d..273f40e 100644 --- a/wallet-hsm/src/main/kotlin/com/wallet/hsm/env/KeyStoreProperties.kt +++ b/wallet-hsm/src/main/kotlin/com/wallet/hsm/env/KeyStoreProperties.kt @@ -1,16 +1,12 @@ package com.wallet.hsm.env - import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.context.annotation.Configuration - @ConfigurationProperties(prefix = "keystore") @Configuration open class KeyStoreProperties { - var dir:String?=null - var password:String="8c79cf3bf0db7ccf54bd75f52b942b9d3154a4d5" - - var eosDepositAddress:String?=null - -} \ No newline at end of file + var dir: String? = null + var password: String = "" + var eosDepositAddress: String? = null +} diff --git a/wallet-hsm/src/main/kotlin/com/wallet/hsm/xservice/impl/HsmXServiceImpl.kt b/wallet-hsm/src/main/kotlin/com/wallet/hsm/xservice/impl/HsmXServiceImpl.kt index 921658e..5499884 100644 --- a/wallet-hsm/src/main/kotlin/com/wallet/hsm/xservice/impl/HsmXServiceImpl.kt +++ b/wallet-hsm/src/main/kotlin/com/wallet/hsm/xservice/impl/HsmXServiceImpl.kt @@ -246,7 +246,9 @@ class HsmXServiceImpl : HsmXService { } companion object { - var identity = Identity.currentIdentity!! + val identity: Identity + get() = Identity.currentIdentity + ?: throw IllegalStateException("Identity not initialized. Ensure ScanKeyStoreConfig has run.") } @Autowired diff --git a/wallet-hsm/src/main/resources/application.yml b/wallet-hsm/src/main/resources/application.yml index f3de426..c61411a 100644 --- a/wallet-hsm/src/main/resources/application.yml +++ b/wallet-hsm/src/main/resources/application.yml @@ -1,17 +1,18 @@ server: - port: 10888 - + port: ${SERVER_PORT:10888} spring: application: - name: cl-hsm -#eureka: -# client: -# service-url: -# default-zone: http://127.0.0.1:8761/eureka/ -# instance: -# instance-id: ${spring.application.name}:${server.port} + name: wallet-hsm keystore: - dir: /Users/pie/temp/tem - eosDepositAddress: + dir: ${KEYSTORE_DIR:/data/keystores} + password: ${KEYSTORE_PASSWORD:} + eosDepositAddress: ${EOS_DEPOSIT_ADDRESS:} + +logging: + level: + root: INFO + com.wallet: ${LOG_LEVEL:INFO} + file: + name: logs/wallet-hsm.log diff --git a/wallet-task/Dockerfile b/wallet-task/Dockerfile index 1ac4fcf..1d61b37 100644 --- a/wallet-task/Dockerfile +++ b/wallet-task/Dockerfile @@ -1,8 +1,25 @@ -FROM openjdk:8-jdk-alpine -VOLUME /tmp -VOLUME /etc/localtime:/etc/localtime -COPY build/libs/cl-task-0.0.1-SNAPSHOT.jar /mnt/cl-task-0.0.1-SNAPSHOT.jar -COPY src/main/resources/application.yml /mnt/application.yml -ENV PORT 10033 +# Stage 1: Build +FROM eclipse-temurin:17-jdk-alpine AS builder +WORKDIR /app +COPY . . +RUN chmod +x ./gradlew && ./gradlew :wallet-task:bootJar --no-daemon -x test + +# Stage 2: Runtime +FROM eclipse-temurin:17-jre-alpine +WORKDIR /app + +RUN addgroup -S wallet && adduser -S wallet -G wallet + +COPY --from=builder /app/wallet-task/build/libs/*.jar app.jar + +ENV PORT=10033 +ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" + EXPOSE $PORT -ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/mnt/cl-task-0.0.1-SNAPSHOT.jar"] \ No newline at end of file + +USER wallet + +HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT}/actuator/health || exit 1 + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dserver.port=${PORT} -jar app.jar"] diff --git a/wallet-task/build.gradle b/wallet-task/build.gradle index 7b8636e..ef97e0a 100644 --- a/wallet-task/build.gradle +++ b/wallet-task/build.gradle @@ -4,8 +4,22 @@ plugins { apply plugin: 'application' -dependencies { - compile project(":wallet-common") +mainClassName = "com.wallet.TaskApplicationKt" +dependencies { + implementation project(":wallet-common") } +jib { + from { + image = 'eclipse-temurin:17-jre-alpine' + } + to { + image = "wallet-task:${project.version}" + } + container { + mainClass = 'com.wallet.TaskApplicationKt' + ports = ['10033'] + jvmFlags = ['-Xms256m', '-Xmx512m', '-Djava.security.egd=file:/dev/./urandom'] + } +} diff --git a/wallet-task/src/main/kotlin/com/wallet/task/config/RabbitMqConfig.kt b/wallet-task/src/main/kotlin/com/wallet/task/config/RabbitMqConfig.kt index cecd105..5c61cb8 100644 --- a/wallet-task/src/main/kotlin/com/wallet/task/config/RabbitMqConfig.kt +++ b/wallet-task/src/main/kotlin/com/wallet/task/config/RabbitMqConfig.kt @@ -1,33 +1,21 @@ package com.wallet.task.config import com.wallet.biz.dict.MqKey -import com.wallet.biz.rpc.EthRpc -import com.wallet.biz.rpc.RpcClient import org.springframework.amqp.core.Binding import org.springframework.amqp.core.BindingBuilder import org.springframework.amqp.core.Queue -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Bean import org.springframework.amqp.core.TopicExchange -import org.springframework.beans.factory.annotation.Autowired -import javax.annotation.PostConstruct - +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration -/** - * Created by pie on 2019/2/22 16: 33. - */ @Configuration open class RabbitMqConfig { - - - //声明队列 @Bean open fun deposit(): Queue { - return Queue(MqKey.DEPOSIT_QUEUE, true) // true表示持久化该队列 + return Queue(MqKey.DEPOSIT_QUEUE, true) } - //声明交互器 @Bean open fun topicExchange(): TopicExchange { return TopicExchange(MqKey.TOPIC_EXCHANGE) @@ -38,13 +26,4 @@ open class RabbitMqConfig { return BindingBuilder.bind(deposit()).to(topicExchange()) .with(MqKey.DEPOSIT_KEY) } - -// @Bean -// open fun binding2(): Binding { -// return BindingBuilder.bind(Queue("qq2")).to(TopicExchange(MqKey.TOPIC_EXCHANGE)) -// .with("foo.aa.#") -// } - - @Autowired - lateinit var rpcClient: RpcClient } diff --git a/wallet-task/src/main/resources/application.yml b/wallet-task/src/main/resources/application.yml index 592a81a..d54d5cf 100644 --- a/wallet-task/src/main/resources/application.yml +++ b/wallet-task/src/main/resources/application.yml @@ -1,35 +1,47 @@ server: - port: 10033 + port: ${SERVER_PORT:10033} spring: application: - name: cl-task + name: wallet-task datasource: - url: jdbc:mysql://127.0.0.1:3306/wallet_db?allowMultiQueries=true&useSSL=false&autoReconnect=true&characterEncoding=UTF-8&autoReconnect=true - username: root - password: 123456 - driver-class-name: com.mysql.jdbc.Driver + url: ${DB_URL:jdbc:mysql://127.0.0.1:3306/wallet_db?allowMultiQueries=true&useSSL=false&characterEncoding=UTF-8&autoReconnect=true} + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:} + driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource -# jpa: -# show-sql: true -# hibernate: -# ddl-auto: update + hikari: + minimum-idle: 5 + maximum-pool-size: 20 + idle-timeout: 300000 + max-lifetime: 1800000 + connection-timeout: 30000 + pool-name: wallet-task-pool + jpa: + open-in-view: false + hibernate: + ddl-auto: none + properties: + hibernate: + dialect: org.hibernate.dialect.MySQLDialect rabbitmq: - host: 192.168.123.83 - port: 5672 - username: wallet - password: wallet -#eureka: -# client: -# service-url: -# default-zone: http://127.0.0.1:8761/eureka/ -# instance: -# instance-id: ${spring.application.name}:${server.port} + host: ${RABBITMQ_HOST:127.0.0.1} + port: ${RABBITMQ_PORT:5672} + username: ${RABBITMQ_USERNAME:guest} + password: ${RABBITMQ_PASSWORD:guest} + xxl: job: - adminAddresses: http://192.168.3.126:8099/xxl-job-admin - appName: cl-task - port: 9999 - accessToken: x + adminAddresses: ${XXL_JOB_ADMIN_ADDRESSES:http://127.0.0.1:8099/xxl-job-admin} + appName: wallet-task + port: ${XXL_JOB_PORT:9999} + accessToken: ${XXL_JOB_ACCESS_TOKEN:} logPath: task-logs - logRetentionDays: 3 + logRetentionDays: 30 + +logging: + level: + root: INFO + com.wallet: ${LOG_LEVEL:INFO} + file: + name: logs/wallet-task.log diff --git a/wallet-task/src/test/kotlin/com/cl/test/Test.kt b/wallet-task/src/test/kotlin/com/cl/test/Test.kt deleted file mode 100644 index 8de8fd9..0000000 --- a/wallet-task/src/test/kotlin/com/cl/test/Test.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.wallet.test - -import com.wallet.TaskApplication -import com.wallet.biz.dict.SysConfigKey -import com.wallet.biz.rpc.RpcClient -import com.wallet.biz.rpc.TrxApi -import org.junit.Test -import org.junit.runner.RunWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.junit4.SpringRunner -import org.springframework.web.client.RestTemplate -import java.math.BigDecimal - -/**
 - * Created by pie on 2019-04-12 16: 06.
 - */ -@RunWith(SpringRunner::class) -@SpringBootTest(classes = [TaskApplication::class]) -class Test { - - - - @Autowired - lateinit var restTemplate: RestTemplate - -} diff --git a/wallet-task/src/test/kotlin/com/wallet/test/TaskApplicationTest.kt b/wallet-task/src/test/kotlin/com/wallet/test/TaskApplicationTest.kt new file mode 100644 index 0000000..ce023f5 --- /dev/null +++ b/wallet-task/src/test/kotlin/com/wallet/test/TaskApplicationTest.kt @@ -0,0 +1,13 @@ +package com.wallet.test + +import com.wallet.TaskApplication +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [TaskApplication::class]) +class TaskApplicationTest { + + @Test + fun contextLoads() { + } +} diff --git a/wallet-webapi/Dockerfile b/wallet-webapi/Dockerfile index 361b451..4af67df 100644 --- a/wallet-webapi/Dockerfile +++ b/wallet-webapi/Dockerfile @@ -1,8 +1,25 @@ -FROM openjdk:8-jdk-alpine -VOLUME /tmp -VOLUME /etc/localtime:/etc/localtime -COPY build/libs/cl-webapi-0.0.1-SNAPSHOT.jar /mnt/cl-webapi-0.0.1-SNAPSHOT.jar -COPY src/main/resources/application.yml /mnt/application.yml -ENV PORT 10001 +# Stage 1: Build +FROM eclipse-temurin:17-jdk-alpine AS builder +WORKDIR /app +COPY . . +RUN chmod +x ./gradlew && ./gradlew :wallet-webapi:bootJar --no-daemon -x test + +# Stage 2: Runtime +FROM eclipse-temurin:17-jre-alpine +WORKDIR /app + +RUN addgroup -S wallet && adduser -S wallet -G wallet + +COPY --from=builder /app/wallet-webapi/build/libs/*.jar app.jar + +ENV PORT=10001 +ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200" + EXPOSE $PORT -ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-Dserver.port=${PORT}","-jar","/mnt/cl-webapi-0.0.1-SNAPSHOT.jar"] \ No newline at end of file + +USER wallet + +HEALTHCHECK --interval=30s --timeout=3s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:${PORT}/actuator/health || exit 1 + +ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dserver.port=${PORT} -jar app.jar"] diff --git a/wallet-webapi/build.gradle b/wallet-webapi/build.gradle index f5739bc..f2a7f86 100644 --- a/wallet-webapi/build.gradle +++ b/wallet-webapi/build.gradle @@ -4,9 +4,22 @@ plugins { apply plugin: 'application' -mainClassName="com.wallet.WebApiApplicationKt" +mainClassName = "com.wallet.WebApiApplicationKt" + dependencies { - compile project(":wallet-common") + implementation project(":wallet-common") } - +jib { + from { + image = 'eclipse-temurin:17-jre-alpine' + } + to { + image = "wallet-webapi:${project.version}" + } + container { + mainClass = 'com.wallet.WebApiApplicationKt' + ports = ['10001'] + jvmFlags = ['-Xms256m', '-Xmx512m', '-Djava.security.egd=file:/dev/./urandom'] + } +} diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/CorsConfig.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/CorsConfig.kt index 17d1f3c..22319cb 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/CorsConfig.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/CorsConfig.kt @@ -1,34 +1,27 @@ package com.wallet.webapi.config -import com.wallet.biz.rpc.RpcClient -import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.web.cors.CorsConfiguration import org.springframework.web.cors.UrlBasedCorsConfigurationSource import org.springframework.web.filter.CorsFilter -import java.math.BigInteger -import javax.annotation.PostConstruct -/**
 - * Created by pie on 2020/12/7 19: 48.
 - */ @Configuration open class CorsConfig { private fun corsConfig(): CorsConfiguration { val corsConfiguration = CorsConfiguration() - corsConfiguration.addAllowedOrigin("*") //允许所有域名访问 - corsConfiguration.addAllowedHeader("*") //允许所有请求头 - corsConfiguration.addAllowedMethod("*") //允许所有的请求类型 + corsConfiguration.addAllowedOriginPattern("*") + corsConfiguration.addAllowedHeader("*") + corsConfiguration.addAllowedMethod("*") corsConfiguration.maxAge = 3600L - corsConfiguration.allowCredentials = true //允许请求携带验证信息(cookie) + corsConfiguration.allowCredentials = true return corsConfiguration } @Bean - open fun corsFilter(): CorsFilter { //存储request与跨域配置信息的容器,基于url的映射 + open fun corsFilter(): CorsFilter { val source = UrlBasedCorsConfigurationSource() source.registerCorsConfiguration("/**", corsConfig()) return CorsFilter(source) diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/WebMvcConfig.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/WebMvcConfig.kt index a8a4e46..dfae070 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/WebMvcConfig.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/WebMvcConfig.kt @@ -1,34 +1,28 @@ package com.wallet.webapi.config - import com.wallet.webapi.config.interceptor.RequestInterceptor import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.annotation.Configuration import org.springframework.web.servlet.config.annotation.CorsRegistry import org.springframework.web.servlet.config.annotation.InterceptorRegistry -import org.springframework.web.servlet.config.annotation.PathMatchConfigurer -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter -import org.springframework.web.util.UrlPathHelper +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer @Configuration -open class WebMvcConfig : WebMvcConfigurerAdapter() { +open class WebMvcConfig : WebMvcConfigurer { override fun addCorsMappings(registry: CorsRegistry) { registry.addMapping("/**") .allowCredentials(true) .allowedHeaders("*") - .allowedOrigins("*") - .allowedMethods("*"); + .allowedOriginPatterns("*") + .allowedMethods("*") } override fun addInterceptors(registry: InterceptorRegistry) { registry.addInterceptor(requestInterceptor) } - - - @Autowired lateinit var requestInterceptor: RequestInterceptor } diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/filter/WebFilter.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/filter/WebFilter.kt index c2cdb2c..6f9668a 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/filter/WebFilter.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/filter/WebFilter.kt @@ -1,38 +1,26 @@ package com.wallet.webapi.config.filter +import jakarta.servlet.* +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier import org.springframework.context.annotation.Configuration import org.springframework.web.servlet.HandlerExceptionResolver -import javax.servlet.* -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse - -/**
 - * Created by pie on 2020/12/7 19: 13.
 - */ @Configuration open class WebFilter : Filter { - override fun destroy() { - - } - override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) { request as HttpServletRequest response as HttpServletResponse try { chain.doFilter(request, response) - } catch (e: Exception) { // 异常捕获,发送到error controller - resolver.resolveException(request, response, null, e); + } catch (e: Exception) { + resolver.resolveException(request, response, null, e) } } - override fun init(filterConfig: FilterConfig?) { - - } - @Autowired @Qualifier("handlerExceptionResolver") lateinit var resolver: HandlerExceptionResolver diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/interceptor/RequestInterceptor.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/interceptor/RequestInterceptor.kt index 48e087e..e479371 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/interceptor/RequestInterceptor.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/config/interceptor/RequestInterceptor.kt @@ -6,20 +6,18 @@ import com.wallet.biz.domain.exception.BizException import com.wallet.biz.service.UserService import com.wallet.biz.service.WhiteService import com.wallet.entity.domain.White +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse +import org.springframework.web.servlet.HandlerInterceptor @Component -open class RequestInterceptor : HandlerInterceptorAdapter() { - - override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any?): Boolean { - val clientIp = request.getHeader("X-Real-IP") +open class RequestInterceptor : HandlerInterceptor { + override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { val requestURI = request.requestURI - if (requestURI!!.contains("swagger") + if (requestURI.contains("swagger") || requestURI.contains("api-docs") || requestURI.contains("/error") || requestURI.contains("ops") @@ -28,7 +26,7 @@ open class RequestInterceptor : HandlerInterceptorAdapter() { return true } - val ip = request.remoteAddr + val ip = request.getHeader("X-Real-IP") ?: request.remoteAddr val find = PageEntity(White()) find.entity.ip = ip val list = whiteService.findByEntity(find).toList() @@ -45,6 +43,4 @@ open class RequestInterceptor : HandlerInterceptorAdapter() { @Autowired lateinit var userService: UserService - - } diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/AdminController.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/AdminController.kt index 29a7325..2ec59bc 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/AdminController.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/AdminController.kt @@ -1,192 +1,180 @@ package com.wallet.webapi.controller - import com.wallet.biz.domain.dict.TokenResponse import com.wallet.biz.xservice.AdminXService import com.wallet.entity.domain.* -import io.swagger.annotations.Api -import io.swagger.annotations.ApiOperation +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.annotation.Resource +import jakarta.servlet.http.HttpServletRequest import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController -import javax.annotation.Resource -import javax.servlet.http.HttpServletRequest -/**
 - * Created by pie on 2020/12/7 13: 05.
 - */ @RestController -@Api(description = "管理后台接口") +@Tag(name = "Admin API", description = "管理后台接口") @RequestMapping("admin") class AdminController { @GetMapping("get_user") - @ApiOperation("获取用户") + @Operation(summary = "获取用户") fun getUser(): TokenResponse { val user = request.getAttribute("user") as User return TokenResponse(user) } @GetMapping("get_addr_list") - @ApiOperation("获取地址清单") + @Operation(summary = "获取地址清单") fun getAddrList(): TokenResponse> { val list = adminXService.getAddrList() return TokenResponse(list) } @GetMapping("get_sys_config_list") - @ApiOperation("获取配置列表") + @Operation(summary = "获取配置列表") fun getSysConfigList(): TokenResponse> { val list = adminXService.getSysConfigList() return TokenResponse(list) } @GetMapping("get_white_list") - @ApiOperation("获取白名单列表") + @Operation(summary = "获取白名单列表") fun getWhiteList(): TokenResponse> { val list = adminXService.getWhiteList() return TokenResponse(list) } @GetMapping("get_address_admin_list") - @ApiOperation("获取管理员地址列表") + @Operation(summary = "获取管理员地址列表") fun getAddressAdminList(): TokenResponse> { val list = adminXService.getAddrAdminList() return TokenResponse(list) } @GetMapping("get_transaction_list") - @ApiOperation("获取充值列表") + @Operation(summary = "获取充值列表") fun getTransactionList(): TokenResponse> { val list = adminXService.getTransactionList() return TokenResponse(list) } @GetMapping("get_withdraw_list") - @ApiOperation("获取提现列表") + @Operation(summary = "获取提现列表") fun getWithdrawList(): TokenResponse> { val list = adminXService.getWithdrawList() return TokenResponse(list) } @GetMapping("get_block_height_list") - @ApiOperation("获取区块高度列表") + @Operation(summary = "获取区块高度列表") fun getBlockHeightList(): TokenResponse> { val list = adminXService.getBlockHeightList() return TokenResponse(list) } - @GetMapping("get_token_list") - @ApiOperation("获取代币列表") + @Operation(summary = "获取代币列表") fun getTokenList(): TokenResponse> { val list = adminXService.getTokenList() return TokenResponse(list) } - @GetMapping("get_addr_admin_list") - @ApiOperation("获得管理员地址列表") - fun getAddrAminList(): TokenResponse> { - val list = adminXService.getAddrAdminList() - return TokenResponse(list) - } - @GetMapping("get_dashboard") - @ApiOperation("获取桌面信息") - fun getDashboard(): TokenResponse> { + @Operation(summary = "获取桌面信息") + fun getDashboard(): TokenResponse> { val map = adminXService.getDashboard() return TokenResponse(map) } @PostMapping("login") - @ApiOperation("登陆") + @Operation(summary = "登陆") fun login(name: String, password: String): TokenResponse { val token = adminXService.login(name, password) return TokenResponse(token) } @PostMapping("add_addr_admin") - @ApiOperation("增加管理员地址") - fun addAddrAdmin(type:Int,address:String,chainType:String): TokenResponse { - adminXService.addAddrAdmin(type,address,chainType) + @Operation(summary = "增加管理员地址") + fun addAddrAdmin(type: Int, address: String, chainType: String): TokenResponse { + adminXService.addAddrAdmin(type, address, chainType) return TokenResponse() } @PostMapping("del_addr_admin") - @ApiOperation("删除管理员地址") - fun delAddrAdmin(id:Long): TokenResponse { + @Operation(summary = "删除管理员地址") + fun delAddrAdmin(id: Long): TokenResponse { adminXService.delAddrAdmin(id) return TokenResponse() } @PostMapping("edit_addr_admin") - @ApiOperation("编辑管理员地址") + @Operation(summary = "编辑管理员地址") fun editAddrAdmin(walletAddressAdmin: AddressAdmin): TokenResponse { adminXService.editAddrAdmin(walletAddressAdmin) return TokenResponse() } @PostMapping("edit_token") - @ApiOperation("编辑代币") + @Operation(summary = "编辑代币") fun editToken(walletToken: Token): TokenResponse { adminXService.editToken(walletToken) return TokenResponse() } @PostMapping("del_token") - @ApiOperation("删除代币") - fun delToken(id:Long): TokenResponse { + @Operation(summary = "删除代币") + fun delToken(id: Long): TokenResponse { adminXService.delToken(id) return TokenResponse() } @PostMapping("edit_block_height") - @ApiOperation("编辑区块高度配置") + @Operation(summary = "编辑区块高度配置") fun editBlockHeight(walletBlockHeight: BlockHeight): TokenResponse { adminXService.editBlockHeight(walletBlockHeight) return TokenResponse() } @PostMapping("del_block_height") - @ApiOperation("删除区块高度配置") - fun delBlockHeight(id:Long): TokenResponse { + @Operation(summary = "删除区块高度配置") + fun delBlockHeight(id: Long): TokenResponse { adminXService.delBlockHeight(id) return TokenResponse() } @PostMapping("edit_config") - @ApiOperation("编辑区块高度配置") + @Operation(summary = "编辑系统配置") fun editConfig(sysConfig: Config): TokenResponse { adminXService.editConfig(sysConfig) return TokenResponse() } @PostMapping("del_config") - @ApiOperation("删除系统配置") - fun delConfig(id:Long): TokenResponse { + @Operation(summary = "删除系统配置") + fun delConfig(id: Long): TokenResponse { adminXService.delConfig(id) return TokenResponse() } @PostMapping("edit_white") - @ApiOperation("编辑白名单") + @Operation(summary = "编辑白名单") fun editWhite(white: White): TokenResponse { adminXService.editWhite(white) return TokenResponse() } @PostMapping("del_white") - @ApiOperation("删除白名单") - fun delWhite(id:Long): TokenResponse { + @Operation(summary = "删除白名单") + fun delWhite(id: Long): TokenResponse { adminXService.delWhite(id) return TokenResponse() } - @Autowired lateinit var adminXService: AdminXService + @Resource lateinit var request: HttpServletRequest } diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/BlockChainController.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/BlockChainController.kt index 894354e..fa91dee 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/BlockChainController.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/BlockChainController.kt @@ -8,29 +8,26 @@ import com.wallet.biz.domain.po.GetTransactionPo import com.wallet.biz.domain.vo.GetRecommendFeeVo import com.wallet.biz.domain.vo.TransactionVo import com.wallet.biz.xservice.BlockChainXService -import io.swagger.annotations.Api -import io.swagger.annotations.ApiOperation +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.beans.factory.annotation.Autowired import org.springframework.web.bind.annotation.* import java.math.BigDecimal -/**
 - * Created by pie on 2020/7/11 16: 05.
 - */ @RestController -@Api(description = "区块链接口") +@Tag(name = "BlockChain API", description = "区块链接口") @RequestMapping("block_chain/v1") class BlockChainController { @GetMapping("get_transaction") - @ApiOperation("查询hash/地址 查询交易(链上查询) type 100查询hash 200查询地址 默认10条") + @Operation(summary = "查询交易", description = "查询hash/地址交易(链上查询) type 100查询hash 200查询地址 默认10条") fun getTransaction( - chain: String?, - tokenAddress: String?, - hash: String?, - address: String?, - type: Int?, - limit: Int? + @RequestParam(required = false) chain: String?, + @RequestParam(required = false) tokenAddress: String?, + @RequestParam(required = false) hash: String?, + @RequestParam(required = false) address: String?, + @RequestParam(required = false) type: Int?, + @RequestParam(required = false) limit: Int? ): TokenResponse> { val getTransactionPo = GetTransactionPo() getTransactionPo.chain = chain @@ -44,30 +41,39 @@ class BlockChainController { } @GetMapping("get_address_balance") - @ApiOperation("查询地址余额(链上查询)") - fun getAddressBalance(address: String?, chain: String?, tokenAddress: String?): TokenResponse { + @Operation(summary = "查询地址余额", description = "链上查询") + fun getAddressBalance( + @RequestParam address: String, + @RequestParam chain: String, + @RequestParam(required = false) tokenAddress: String? + ): TokenResponse { val getAddressBalancePo = GetAddressBalancePo() getAddressBalancePo.address = address getAddressBalancePo.chain = chain getAddressBalancePo.tokenAddress = tokenAddress val any = blockChainXService.getAddressBalance( - getAddressBalancePo.chain!!, - getAddressBalancePo.address!!, - getAddressBalancePo.tokenAddress + getAddressBalancePo.chain!!, + getAddressBalancePo.address!!, + getAddressBalancePo.tokenAddress ) return TokenResponse(any) } @GetMapping("get_recommend_fee") - @ApiOperation("获取低中高阶手续费") - fun getRecommendFee(chain: String): TokenResponse { + @Operation(summary = "获取推荐手续费", description = "获取低中高阶手续费") + fun getRecommendFee(@RequestParam chain: String): TokenResponse { val vo = blockChainXService.getRecommendFee(chain) return TokenResponse(vo) } @GetMapping("calculation_fee") - @ApiOperation("计算手续费数量") - fun calculationFee(gas: Int, gasLimit: Long?, from: String?, chain: String): TokenResponse { + @Operation(summary = "计算手续费数量") + fun calculationFee( + @RequestParam gas: Int, + @RequestParam(required = false) gasLimit: Long?, + @RequestParam(required = false) from: String?, + @RequestParam chain: String + ): TokenResponse { val po = CalculationFeePo() po.chain = chain po.from = from @@ -78,14 +84,13 @@ class BlockChainController { } @GetMapping("get_support_token") - @ApiOperation("获得支持币种") + @Operation(summary = "获得支持币种") fun getSupportToken(): TokenResponse> { val chainList = TokenKey.getChainList() val symbolList = TokenKey.getSymbolList() return TokenResponse(mapOf("chain" to chainList, "symbol" to symbolList)) } - @Autowired lateinit var blockChainXService: BlockChainXService } diff --git a/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/WalletController.kt b/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/WalletController.kt index 611a557..cb1043d 100644 --- a/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/WalletController.kt +++ b/wallet-webapi/src/main/kotlin/com/wallet/webapi/controller/WalletController.kt @@ -6,44 +6,40 @@ import com.wallet.biz.domain.po.* import com.wallet.biz.domain.vo.TransactionLogVo import com.wallet.biz.xservice.WalletXService import com.wallet.entity.domain.Deposit -import io.swagger.annotations.Api -import io.swagger.annotations.ApiOperation +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.tags.Tag import org.consenlabs.tokencore.wallet.model.ChainType import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.domain.Page import org.springframework.web.bind.annotation.* import java.math.BigDecimal -/**
 - * Created by pie on 2019-04-11 16: 36.
 - */ @RestController -@Api(description = "本地钱包接口") +@Tag(name = "Wallet API", description = "本地钱包接口") @RequestMapping("wallet/v1") class WalletController { - @GetMapping("get_address") - @ApiOperation("获得地址 例如/getaddr/BITCOIN chainType(btc:${ChainType.BITCOIN}|eth:${ChainType.ETHEREUM}|trx:${ChainType.TRON})") - fun getAddress(chain: String, num: Int): TokenResponse> { + @PostMapping("get_address") + @Operation(summary = "获得地址", description = "chainType(btc:BITCOIN|eth:ETHEREUM|trx:TRON)") + fun getAddress(@RequestParam chain: String, @RequestParam num: Int): TokenResponse> { val getAddressPo = GetAddressPo() getAddressPo.chain = chain getAddressPo.num = num - val list = walletXService.getAddress(getAddressPo.chain!!.toUpperCase(), getAddressPo.num!!) -// val list= arrayListOf("18fiBrC2Gnnih53S9Aq5hiuNRD21xm5o7p","1LrtBDVdxDnq7WVoLmSLJT7iw6GLKZhSGt") + val list = walletXService.getAddress(getAddressPo.chain!!.uppercase(), getAddressPo.num!!) return TokenResponse(list) } - @GetMapping("send") - @ApiOperation("提现(指定提现from地址,不指定将从热钱包转出)") + @PostMapping("send") + @Operation(summary = "提现", description = "指定提现from地址,不指定将从热钱包转出") fun send( - amount: BigDecimal, - chain: String, - from: String?, - symbol: String?, - to: String, - gas: Int?, - gasLimit: Long?, - data: String? + @RequestParam amount: BigDecimal, + @RequestParam chain: String, + @RequestParam(required = false) from: String?, + @RequestParam(required = false) symbol: String?, + @RequestParam to: String, + @RequestParam(required = false) gas: Int?, + @RequestParam(required = false) gasLimit: Long?, + @RequestParam(required = false) data: String? ): TokenResponse { val sendPo = SendPo() sendPo.amount = amount @@ -59,8 +55,8 @@ class WalletController { } @GetMapping("get_hot_address") - @ApiOperation("查询热钱包地址 type 100发送钱包300gas钱包") - fun getHotAddress(chain: String, type: Int): TokenResponse?> { + @Operation(summary = "查询热钱包地址", description = "type 100发送钱包300gas钱包") + fun getHotAddress(@RequestParam chain: String, @RequestParam type: Int): TokenResponse?> { val getHotAddressPo = GetHotAddressPo() getHotAddressPo.chain = chain getHotAddressPo.type = type @@ -68,9 +64,9 @@ class WalletController { return TokenResponse(addr) } - @GetMapping("create_hot_address") - @ApiOperation("生成热钱包地址 type(100发送钱包 300gas钱包)") - fun createHotAddress(type: Int, chain: String): TokenResponse { + @PostMapping("create_hot_address") + @Operation(summary = "生成热钱包地址", description = "type(100发送钱包 300gas钱包)") + fun createHotAddress(@RequestParam type: Int, @RequestParam chain: String): TokenResponse { val createHotAddressPo = CreateHotAddressPo() createHotAddressPo.type = type createHotAddressPo.chain = chain @@ -79,8 +75,8 @@ class WalletController { } @GetMapping("check_address") - @ApiOperation("检测地址私钥存在") - fun checkAddress(address: String, chain: String): TokenResponse { + @Operation(summary = "检测地址私钥存在") + fun checkAddress(@RequestParam address: String, @RequestParam chain: String): TokenResponse { val checkAddressPo = CheckAddressPo() checkAddressPo.address = address checkAddressPo.chain = chain @@ -89,26 +85,26 @@ class WalletController { } @GetMapping("get_new_deposit") - @ApiOperation("获得充值交易(备用) 拿一次就消失") + @Operation(summary = "获得充值交易(备用) 拿一次就消失") fun getDepositTransaction(): TokenResponse> { val list = walletXService.getDepositTransactionAndSave() return TokenResponse(list) } @GetMapping("get_transaction") - @ApiOperation("获得记录 type(充值 100 |提现 200| 归集 300|发送gas费 400 )") - fun getLocalTransaction(type: Int, page: Int, size: Int): TokenResponse> { - val list = walletXService.getLocalTransaction( - type, - page, - size - ) + @Operation(summary = "获得记录", description = "type(充值 100 |提现 200| 归集 300|发送gas费 400)") + fun getLocalTransaction( + @RequestParam type: Int, + @RequestParam page: Int, + @RequestParam size: Int + ): TokenResponse> { + val list = walletXService.getLocalTransaction(type, page, size) return TokenResponse(list) } - @GetMapping("export_wallet") - @ApiOperation("导出私钥/助记词(比特币只能导入导出助记词) |私钥${KeyType.PRIVATE}|助记词${KeyType.MNEMONIC}") - fun exportWallet(walletCode: String, type: Int): TokenResponse { + @PostMapping("export_wallet") + @Operation(summary = "导出私钥/助记词", description = "比特币只能导入导出助记词 |私钥${KeyType.PRIVATE}|助记词${KeyType.MNEMONIC}") + fun exportWallet(@RequestParam walletCode: String, @RequestParam type: Int): TokenResponse { val exportWalletPo = ExportWalletPo() exportWalletPo.walletCode = walletCode exportWalletPo.type = type @@ -116,9 +112,13 @@ class WalletController { return TokenResponse(key) } - @GetMapping("import_wallet") - @ApiOperation("导入私钥/助记词(比特币只能导入导出助记词) |私钥${KeyType.PRIVATE}|助记词${KeyType.MNEMONIC}") - fun importWallet(type: Int, chain: String, key: String): TokenResponse { + @PostMapping("import_wallet") + @Operation(summary = "导入私钥/助记词", description = "比特币只能导入导出助记词 |私钥${KeyType.PRIVATE}|助记词${KeyType.MNEMONIC}") + fun importWallet( + @RequestParam type: Int, + @RequestParam chain: String, + @RequestParam key: String + ): TokenResponse { val importWalletPo = ImportWalletPo() importWalletPo.type = type importWalletPo.chain = chain @@ -127,52 +127,20 @@ class WalletController { return TokenResponse(address) } - @GetMapping("remove_useless_wallet") - @ApiOperation("清除无用的钱包") + @PostMapping("remove_useless_wallet") + @Operation(summary = "清除无用的钱包") fun removeUselessWallet(): TokenResponse { walletXService.removeUselessWallet() return TokenResponse() } @GetMapping("check_tx_status") - @ApiOperation("检查交易状态") - fun checkTxStatus(hash: String, chain: String): TokenResponse { + @Operation(summary = "检查交易状态") + fun checkTxStatus(@RequestParam hash: String, @RequestParam chain: String): TokenResponse { val status = walletXService.checkTxStatus(hash, chain) return TokenResponse(status) } - -// @GetMapping("put_all_address_to_wait_import") -// @ApiOperation("把所有地址导入到节点") -// fun putAllAddressToWaitImport(): TokenResponse{ -// walletXService.putAllAddressToWaitImport() -// return TokenResponse() -// } - -// @GetMapping("add_wait_collect") -// @ApiOperation("添加待归集地址") -// fun addWaitCollect(): TokenResponse { -// walletXService.addWaitCollect() -// return TokenResponse() -// } - -// @PostMapping("rescan_transaction") -// @ApiOperation("重扫充值交易") -// fun rescanTransaction(@RequestBody rescanTransactionPo:RescanTransactionPo): TokenResponse{ -// walletXService.rescanTransaction(rescanTransactionPo) -// return TokenResponse() -// } -// -// @PostMapping("rescan_block") -// @ApiOperation("重扫区块高度") -// fun rescanBlock(@RequestBody rescanBlockPo:RescanBlockPo): TokenResponse{ -// walletXService.rescanBlock(rescanBlockPo) -// return TokenResponse() -// } - - @Autowired lateinit var walletXService: WalletXService - - } diff --git a/wallet-webapi/src/main/resources/application.yml b/wallet-webapi/src/main/resources/application.yml index 82065e1..5d24c3d 100644 --- a/wallet-webapi/src/main/resources/application.yml +++ b/wallet-webapi/src/main/resources/application.yml @@ -1,26 +1,35 @@ server: - port: 10001 - + port: ${SERVER_PORT:10001} spring: application: - name: cl-webapi + name: wallet-webapi datasource: - url: jdbc:mysql://127.0.0.1:3306/wallet_db?allowMultiQueries=true&useSSL=false&characterEncoding=UTF-8&autoReconnect=true - username: root - password: 123456 - driver-class-name: com.mysql.jdbc.Driver + url: ${DB_URL:jdbc:mysql://127.0.0.1:3306/wallet_db?allowMultiQueries=true&useSSL=false&characterEncoding=UTF-8&autoReconnect=true} + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:} + driver-class-name: com.mysql.cj.jdbc.Driver type: com.zaxxer.hikari.HikariDataSource + hikari: + minimum-idle: 5 + maximum-pool-size: 20 + idle-timeout: 300000 + max-lifetime: 1800000 + connection-timeout: 30000 + pool-name: wallet-webapi-pool jackson: date-format: yyyy-MM-dd HH:mm -# jpa: -# show-sql: true -# hibernate: -# ddl-auto: update + jpa: + open-in-view: false + hibernate: + ddl-auto: none + properties: + hibernate: + dialect: org.hibernate.dialect.MySQLDialect -#eureka: -# client: -# service-url: -# default-zone: http://127.0.0.1:8761/eureka/ -# instance: -# instance-id: ${spring.application.name}:${server.port} +logging: + level: + root: INFO + com.wallet: ${LOG_LEVEL:INFO} + file: + name: logs/wallet-webapi.log diff --git a/wallet-webapi/src/test/kotlin/com/wallet/test/WebApiApplicationTest.kt b/wallet-webapi/src/test/kotlin/com/wallet/test/WebApiApplicationTest.kt new file mode 100644 index 0000000..667934c --- /dev/null +++ b/wallet-webapi/src/test/kotlin/com/wallet/test/WebApiApplicationTest.kt @@ -0,0 +1,13 @@ +package com.wallet.test + +import com.wallet.WebApiApplication +import org.junit.jupiter.api.Test +import org.springframework.boot.test.context.SpringBootTest + +@SpringBootTest(classes = [WebApiApplication::class]) +class WebApiApplicationTest { + + @Test + fun contextLoads() { + } +} diff --git a/wallet-webapi/src/test/kotlin/con/wallet/T.kt b/wallet-webapi/src/test/kotlin/con/wallet/T.kt deleted file mode 100644 index c768aa8..0000000 --- a/wallet-webapi/src/test/kotlin/con/wallet/T.kt +++ /dev/null @@ -1,37 +0,0 @@ -//package con.wallet -// -//import com.wallet.WebApiApplication -//import com.wallet.biz.rpc.TrxApi -//import com.wallet.biz.utils.TRONUtils -//import org.junit.Test -//import org.junit.runner.RunWith -//import org.springframework.beans.factory.annotation.Autowired -//import org.springframework.boot.test.context.SpringBootTest -//import org.springframework.test.context.junit4.SpringRunner -//import org.springframework.web.client.RestTemplate -// -//@RunWith(SpringRunner::class) -//@SpringBootTest(classes=[WebApiApplication::class]) -//class T { -// -// @Test -// fun t(){ -// val balance=tronUtils.getContractBalance("TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t","TCMbJvEtbwVfNYpzjj4kGAufGTgsek9w45") -// -// println(balance) -// -// } -// -// @Test -// fun f() { -// val api = TrxApi("http://13.127.47.162:8090", restTemplate) -// val node = api.easyTransferByPrivate("c071a24e1a81556a6ed5ed41897a3566c14ea3bc8d81d06bbd854d4741db45d1","TQxd3QfuvRuZbZC6vRyw2ummQ6Ftv16xeo", 1) -// println(node) -// } -// -// @Autowired -// lateinit var tronUtils: TRONUtils -// -// @Autowired -// lateinit var restTemplate: RestTemplate -//} \ No newline at end of file