rwadurian/backend/services/mining-blockchain-service/src/api/controllers/transfer.controller.ts

191 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Controller, Post, Body, Get, Param } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiProperty, ApiParam } from '@nestjs/swagger';
import { IsString, IsNotEmpty, Matches, IsNumberString } from 'class-validator';
import { Erc20TransferService, TransferResult, TokenType } from '@/domain/services/erc20-transfer.service';
import { ChainTypeEnum } from '@/domain/enums';
/**
* dUSDT 转账请求 DTO
*/
class TransferDusdtDto {
@ApiProperty({ description: '接收者 Kava 地址', example: '0x1234567890abcdef1234567890abcdef12345678' })
@IsString()
@IsNotEmpty()
@Matches(/^0x[a-fA-F0-9]{40}$/, { message: 'Invalid EVM address format' })
toAddress: string;
@ApiProperty({ description: '转账金额(人类可读格式)', example: '100.5' })
@IsString()
@IsNotEmpty()
@IsNumberString({}, { message: 'Amount must be a valid number string' })
amount: string;
}
/**
* 转账结果响应 DTO
*/
class TransferResponseDto {
@ApiProperty({ description: '是否成功' })
success: boolean;
@ApiProperty({ description: '交易哈希', required: false })
txHash?: string;
@ApiProperty({ description: '错误信息', required: false })
error?: string;
@ApiProperty({ description: '消耗的 Gas', required: false })
gasUsed?: string;
@ApiProperty({ description: '区块高度', required: false })
blockNumber?: number;
}
/**
* 余额响应 DTO
*/
class BalanceResponseDto {
@ApiProperty({ description: '热钱包地址' })
address: string;
@ApiProperty({ description: 'dUSDT 余额' })
balance: string;
@ApiProperty({ description: '链类型' })
chain: string;
}
/**
* dUSDT 转账控制器
* 供 trading-service C2C Bot 调用
*/
@ApiTags('Transfer')
@Controller('transfer')
export class TransferController {
constructor(private readonly erc20TransferService: Erc20TransferService) {}
@Post('dusdt')
@ApiOperation({ summary: '转账 dUSDT 到指定地址' })
@ApiResponse({ status: 200, description: '转账结果', type: TransferResponseDto })
@ApiResponse({ status: 400, description: '参数错误' })
@ApiResponse({ status: 500, description: '转账失败' })
async transferDusdt(@Body() dto: TransferDusdtDto): Promise<TransferResponseDto> {
const result: TransferResult = await this.erc20TransferService.transferUsdt(
ChainTypeEnum.KAVA,
dto.toAddress,
dto.amount,
);
return {
success: result.success,
txHash: result.txHash,
error: result.error,
gasUsed: result.gasUsed,
blockNumber: result.blockNumber,
};
}
@Get('dusdt/balance')
@ApiOperation({ summary: '查询热钱包 dUSDT 余额' })
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
async getHotWalletBalance(): Promise<BalanceResponseDto> {
const address = this.erc20TransferService.getHotWalletAddress(ChainTypeEnum.KAVA);
const balance = await this.erc20TransferService.getHotWalletBalance(ChainTypeEnum.KAVA);
return {
address: address || '',
balance,
chain: 'KAVA',
};
}
@Get('status')
@ApiOperation({ summary: '检查转账服务状态' })
@ApiResponse({ status: 200, description: '服务状态' })
async getStatus(): Promise<{ configured: boolean; hotWalletAddress: string | null }> {
const configured = this.erc20TransferService.isConfigured(ChainTypeEnum.KAVA);
const hotWalletAddress = this.erc20TransferService.getHotWalletAddress(ChainTypeEnum.KAVA);
return {
configured,
hotWalletAddress,
};
}
// ============ eUSDT (积分股) 转账接口 ============
@Post('eusdt')
@ApiOperation({ summary: '转账 eUSDT积分股到指定地址' })
@ApiResponse({ status: 200, description: '转账结果', type: TransferResponseDto })
@ApiResponse({ status: 400, description: '参数错误' })
@ApiResponse({ status: 500, description: '转账失败' })
async transferEusdt(@Body() dto: TransferDusdtDto): Promise<TransferResponseDto> {
const result: TransferResult = await this.erc20TransferService.transferToken(
ChainTypeEnum.KAVA,
'EUSDT',
dto.toAddress,
dto.amount,
);
return {
success: result.success,
txHash: result.txHash,
error: result.error,
gasUsed: result.gasUsed,
blockNumber: result.blockNumber,
};
}
@Get('eusdt/balance')
@ApiOperation({ summary: '查询热钱包 eUSDT积分股余额' })
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
async getEusdtBalance(): Promise<BalanceResponseDto> {
const address = this.erc20TransferService.getHotWalletAddress(ChainTypeEnum.KAVA);
const balance = await this.erc20TransferService.getTokenBalance(ChainTypeEnum.KAVA, 'EUSDT');
return {
address: address || '',
balance,
chain: 'KAVA',
};
}
// ============ fUSDT (积分值) 转账接口 ============
@Post('fusdt')
@ApiOperation({ summary: '转账 fUSDT积分值到指定地址' })
@ApiResponse({ status: 200, description: '转账结果', type: TransferResponseDto })
@ApiResponse({ status: 400, description: '参数错误' })
@ApiResponse({ status: 500, description: '转账失败' })
async transferFusdt(@Body() dto: TransferDusdtDto): Promise<TransferResponseDto> {
const result: TransferResult = await this.erc20TransferService.transferToken(
ChainTypeEnum.KAVA,
'FUSDT',
dto.toAddress,
dto.amount,
);
return {
success: result.success,
txHash: result.txHash,
error: result.error,
gasUsed: result.gasUsed,
blockNumber: result.blockNumber,
};
}
@Get('fusdt/balance')
@ApiOperation({ summary: '查询热钱包 fUSDT积分值余额' })
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
async getFusdtBalance(): Promise<BalanceResponseDto> {
const address = this.erc20TransferService.getHotWalletAddress(ChainTypeEnum.KAVA);
const balance = await this.erc20TransferService.getTokenBalance(ChainTypeEnum.KAVA, 'FUSDT');
return {
address: address || '',
balance,
chain: 'KAVA',
};
}
}