feat(mining-blockchain): 支持 eUSDT 和 fUSDT 独立做市商钱包
- 新增 EUSDT_MARKET_MAKER_USERNAME/ADDRESS 配置 - 新增 FUSDT_MARKET_MAKER_USERNAME/ADDRESS 配置 - mpc-signing.client.ts: 分离 eUSDT 和 fUSDT 做市商签名方法 - erc20-transfer.service.ts: 根据代币类型选择对应钱包转账 - transfer.controller.ts: 更新余额查询和状态接口 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
aa33803d08
commit
3b95a8a332
|
|
@ -282,9 +282,12 @@ services:
|
||||||
# C2C Bot 热钱包 (MPC)
|
# C2C Bot 热钱包 (MPC)
|
||||||
HOT_WALLET_USERNAME: ${HOT_WALLET_USERNAME:-}
|
HOT_WALLET_USERNAME: ${HOT_WALLET_USERNAME:-}
|
||||||
HOT_WALLET_ADDRESS: ${HOT_WALLET_ADDRESS:-}
|
HOT_WALLET_ADDRESS: ${HOT_WALLET_ADDRESS:-}
|
||||||
# 做市商钱包 (MPC) - 用于 eUSDT/fUSDT 转账
|
# eUSDT (积分股) 做市商钱包 (MPC)
|
||||||
MARKET_MAKER_MPC_USERNAME: ${MARKET_MAKER_MPC_USERNAME:-}
|
EUSDT_MARKET_MAKER_USERNAME: ${EUSDT_MARKET_MAKER_USERNAME:-}
|
||||||
MARKET_MAKER_WALLET_ADDRESS: ${MARKET_MAKER_WALLET_ADDRESS:-}
|
EUSDT_MARKET_MAKER_ADDRESS: ${EUSDT_MARKET_MAKER_ADDRESS:-}
|
||||||
|
# fUSDT (积分值) 做市商钱包 (MPC)
|
||||||
|
FUSDT_MARKET_MAKER_USERNAME: ${FUSDT_MARKET_MAKER_USERNAME:-}
|
||||||
|
FUSDT_MARKET_MAKER_ADDRESS: ${FUSDT_MARKET_MAKER_ADDRESS:-}
|
||||||
# 区块扫描配置
|
# 区块扫描配置
|
||||||
BLOCK_SCAN_INTERVAL_MS: ${BLOCK_SCAN_INTERVAL_MS:-5000}
|
BLOCK_SCAN_INTERVAL_MS: ${BLOCK_SCAN_INTERVAL_MS:-5000}
|
||||||
BLOCK_CONFIRMATIONS_REQUIRED: ${BLOCK_CONFIRMATIONS_REQUIRED:-12}
|
BLOCK_CONFIRMATIONS_REQUIRED: ${BLOCK_CONFIRMATIONS_REQUIRED:-12}
|
||||||
|
|
|
||||||
|
|
@ -77,13 +77,20 @@ HOT_WALLET_USERNAME=c2c-bot-wallet
|
||||||
HOT_WALLET_ADDRESS=
|
HOT_WALLET_ADDRESS=
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 做市商 MPC 钱包(用于 eUSDT/fUSDT 转账)
|
# eUSDT (积分股) 做市商 MPC 钱包
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 做市商 MPC 用户名(用于签名转账交易)
|
# MPC 用户名(用于签名转账交易)
|
||||||
MARKET_MAKER_MPC_USERNAME=
|
EUSDT_MARKET_MAKER_USERNAME=
|
||||||
|
# 钱包地址(EVM 地址)
|
||||||
|
EUSDT_MARKET_MAKER_ADDRESS=
|
||||||
|
|
||||||
# 做市商钱包地址(EVM 地址)
|
# =============================================================================
|
||||||
MARKET_MAKER_WALLET_ADDRESS=
|
# fUSDT (积分值) 做市商 MPC 钱包
|
||||||
|
# =============================================================================
|
||||||
|
# MPC 用户名(用于签名转账交易)
|
||||||
|
FUSDT_MARKET_MAKER_USERNAME=
|
||||||
|
# 钱包地址(EVM 地址)
|
||||||
|
FUSDT_MARKET_MAKER_ADDRESS=
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# 区块扫描配置
|
# 区块扫描配置
|
||||||
|
|
|
||||||
|
|
@ -138,11 +138,11 @@ export class TransferController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('eusdt/balance')
|
@Get('eusdt/balance')
|
||||||
@ApiOperation({ summary: '查询做市商钱包 eUSDT(积分股)余额' })
|
@ApiOperation({ summary: '查询 eUSDT 做市商钱包余额' })
|
||||||
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
|
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
|
||||||
async getEusdtBalance(): Promise<BalanceResponseDto> {
|
async getEusdtBalance(): Promise<BalanceResponseDto> {
|
||||||
const address = this.erc20TransferService.getMarketMakerAddress(ChainTypeEnum.KAVA);
|
const address = this.erc20TransferService.getEusdtMarketMakerAddress(ChainTypeEnum.KAVA);
|
||||||
const balance = await this.erc20TransferService.getMarketMakerTokenBalance(ChainTypeEnum.KAVA, 'EUSDT');
|
const balance = await this.erc20TransferService.getEusdtMarketMakerTokenBalance(ChainTypeEnum.KAVA);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
address: address || '',
|
address: address || '',
|
||||||
|
|
@ -177,11 +177,11 @@ export class TransferController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('fusdt/balance')
|
@Get('fusdt/balance')
|
||||||
@ApiOperation({ summary: '查询做市商钱包 fUSDT(积分值)余额' })
|
@ApiOperation({ summary: '查询 fUSDT 做市商钱包余额' })
|
||||||
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
|
@ApiResponse({ status: 200, description: '余额信息', type: BalanceResponseDto })
|
||||||
async getFusdtBalance(): Promise<BalanceResponseDto> {
|
async getFusdtBalance(): Promise<BalanceResponseDto> {
|
||||||
const address = this.erc20TransferService.getMarketMakerAddress(ChainTypeEnum.KAVA);
|
const address = this.erc20TransferService.getFusdtMarketMakerAddress(ChainTypeEnum.KAVA);
|
||||||
const balance = await this.erc20TransferService.getMarketMakerTokenBalance(ChainTypeEnum.KAVA, 'FUSDT');
|
const balance = await this.erc20TransferService.getFusdtMarketMakerTokenBalance(ChainTypeEnum.KAVA);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
address: address || '',
|
address: address || '',
|
||||||
|
|
@ -195,13 +195,19 @@ export class TransferController {
|
||||||
@Get('market-maker/status')
|
@Get('market-maker/status')
|
||||||
@ApiOperation({ summary: '检查做市商转账服务状态' })
|
@ApiOperation({ summary: '检查做市商转账服务状态' })
|
||||||
@ApiResponse({ status: 200, description: '服务状态' })
|
@ApiResponse({ status: 200, description: '服务状态' })
|
||||||
async getMarketMakerStatus(): Promise<{ configured: boolean; marketMakerAddress: string | null }> {
|
async getMarketMakerStatus(): Promise<{
|
||||||
const configured = this.erc20TransferService.isMarketMakerConfigured(ChainTypeEnum.KAVA);
|
eusdt: { configured: boolean; address: string | null };
|
||||||
const marketMakerAddress = this.erc20TransferService.getMarketMakerAddress(ChainTypeEnum.KAVA);
|
fusdt: { configured: boolean; address: string | null };
|
||||||
|
}> {
|
||||||
return {
|
return {
|
||||||
configured,
|
eusdt: {
|
||||||
marketMakerAddress,
|
configured: this.erc20TransferService.isEusdtMarketMakerConfigured(ChainTypeEnum.KAVA),
|
||||||
|
address: this.erc20TransferService.getEusdtMarketMakerAddress(ChainTypeEnum.KAVA),
|
||||||
|
},
|
||||||
|
fusdt: {
|
||||||
|
configured: this.erc20TransferService.isFusdtMarketMakerConfigured(ChainTypeEnum.KAVA),
|
||||||
|
address: this.erc20TransferService.getFusdtMarketMakerAddress(ChainTypeEnum.KAVA),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,10 +38,14 @@ export interface IMpcSigningClient {
|
||||||
isConfigured(): boolean;
|
isConfigured(): boolean;
|
||||||
getHotWalletAddress(): string;
|
getHotWalletAddress(): string;
|
||||||
signMessage(messageHash: string): Promise<string>;
|
signMessage(messageHash: string): Promise<string>;
|
||||||
// 做市商钱包
|
// eUSDT (积分股) 做市商钱包
|
||||||
isMarketMakerConfigured(): boolean;
|
isEusdtMarketMakerConfigured(): boolean;
|
||||||
getMarketMakerAddress(): string;
|
getEusdtMarketMakerAddress(): string;
|
||||||
signMessageAsMarketMaker(messageHash: string): Promise<string>;
|
signMessageAsEusdtMarketMaker(messageHash: string): Promise<string>;
|
||||||
|
// fUSDT (积分值) 做市商钱包
|
||||||
|
isFusdtMarketMakerConfigured(): boolean;
|
||||||
|
getFusdtMarketMakerAddress(): string;
|
||||||
|
signMessageAsFusdtMarketMaker(messageHash: string): Promise<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MPC_SIGNING_CLIENT = Symbol('MPC_SIGNING_CLIENT');
|
export const MPC_SIGNING_CLIENT = Symbol('MPC_SIGNING_CLIENT');
|
||||||
|
|
@ -58,8 +62,10 @@ export class Erc20TransferService {
|
||||||
private readonly providers: Map<ChainTypeEnum, JsonRpcProvider> = new Map();
|
private readonly providers: Map<ChainTypeEnum, JsonRpcProvider> = new Map();
|
||||||
// C2C Bot 热钱包地址
|
// C2C Bot 热钱包地址
|
||||||
private readonly hotWalletAddress: string;
|
private readonly hotWalletAddress: string;
|
||||||
// 做市商钱包地址
|
// eUSDT (积分股) 做市商钱包地址
|
||||||
private readonly marketMakerAddress: string;
|
private readonly eusdtMarketMakerAddress: string;
|
||||||
|
// fUSDT (积分值) 做市商钱包地址
|
||||||
|
private readonly fusdtMarketMakerAddress: string;
|
||||||
private mpcSigningClient: IMpcSigningClient | null = null;
|
private mpcSigningClient: IMpcSigningClient | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -67,7 +73,8 @@ export class Erc20TransferService {
|
||||||
private readonly chainConfig: ChainConfigService,
|
private readonly chainConfig: ChainConfigService,
|
||||||
) {
|
) {
|
||||||
this.hotWalletAddress = this.configService.get<string>('HOT_WALLET_ADDRESS', '');
|
this.hotWalletAddress = this.configService.get<string>('HOT_WALLET_ADDRESS', '');
|
||||||
this.marketMakerAddress = this.configService.get<string>('MARKET_MAKER_WALLET_ADDRESS', '');
|
this.eusdtMarketMakerAddress = this.configService.get<string>('EUSDT_MARKET_MAKER_ADDRESS', '');
|
||||||
|
this.fusdtMarketMakerAddress = this.configService.get<string>('FUSDT_MARKET_MAKER_ADDRESS', '');
|
||||||
this.initializeProviders();
|
this.initializeProviders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,11 +106,18 @@ export class Erc20TransferService {
|
||||||
this.logger.warn('[INIT] HOT_WALLET_ADDRESS not configured, C2C transfers will fail');
|
this.logger.warn('[INIT] HOT_WALLET_ADDRESS not configured, C2C transfers will fail');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查做市商钱包地址配置
|
// 检查 eUSDT 做市商钱包地址配置
|
||||||
if (this.marketMakerAddress) {
|
if (this.eusdtMarketMakerAddress) {
|
||||||
this.logger.log(`[INIT] Market Maker wallet address configured: ${this.marketMakerAddress}`);
|
this.logger.log(`[INIT] eUSDT Market Maker address configured: ${this.eusdtMarketMakerAddress}`);
|
||||||
} else {
|
} else {
|
||||||
this.logger.warn('[INIT] MARKET_MAKER_WALLET_ADDRESS not configured, Market Maker transfers will fail');
|
this.logger.warn('[INIT] EUSDT_MARKET_MAKER_ADDRESS not configured');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查 fUSDT 做市商钱包地址配置
|
||||||
|
if (this.fusdtMarketMakerAddress) {
|
||||||
|
this.logger.log(`[INIT] fUSDT Market Maker address configured: ${this.fusdtMarketMakerAddress}`);
|
||||||
|
} else {
|
||||||
|
this.logger.warn('[INIT] FUSDT_MARKET_MAKER_ADDRESS not configured');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,10 +130,17 @@ export class Erc20TransferService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取做市商钱包地址
|
* 获取 eUSDT 做市商钱包地址
|
||||||
*/
|
*/
|
||||||
getMarketMakerAddress(chainType: ChainTypeEnum): string | null {
|
getEusdtMarketMakerAddress(chainType: ChainTypeEnum): string | null {
|
||||||
return this.marketMakerAddress || null;
|
return this.eusdtMarketMakerAddress || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 fUSDT 做市商钱包地址
|
||||||
|
*/
|
||||||
|
getFusdtMarketMakerAddress(chainType: ChainTypeEnum): string | null {
|
||||||
|
return this.fusdtMarketMakerAddress || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -585,12 +606,21 @@ export class Erc20TransferService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查做市商钱包是否已配置
|
* 检查 eUSDT 做市商钱包是否已配置
|
||||||
*/
|
*/
|
||||||
isMarketMakerConfigured(chainType: ChainTypeEnum): boolean {
|
isEusdtMarketMakerConfigured(chainType: ChainTypeEnum): boolean {
|
||||||
return this.providers.has(chainType) &&
|
return this.providers.has(chainType) &&
|
||||||
!!this.marketMakerAddress &&
|
!!this.eusdtMarketMakerAddress &&
|
||||||
!!this.mpcSigningClient?.isMarketMakerConfigured();
|
!!this.mpcSigningClient?.isEusdtMarketMakerConfigured();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 fUSDT 做市商钱包是否已配置
|
||||||
|
*/
|
||||||
|
isFusdtMarketMakerConfigured(chainType: ChainTypeEnum): boolean {
|
||||||
|
return this.providers.has(chainType) &&
|
||||||
|
!!this.fusdtMarketMakerAddress &&
|
||||||
|
!!this.mpcSigningClient?.isFusdtMarketMakerConfigured();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -608,10 +638,14 @@ export class Erc20TransferService {
|
||||||
toAddress: string,
|
toAddress: string,
|
||||||
amount: string,
|
amount: string,
|
||||||
): Promise<TransferResult> {
|
): Promise<TransferResult> {
|
||||||
const tokenName = tokenType === 'EUSDT' ? '积分股' : tokenType === 'FUSDT' ? '积分值' : 'dUSDT';
|
// 根据代币类型选择对应的做市商钱包
|
||||||
this.logger.log(`[MM-TRANSFER] Starting Market Maker ${tokenType} (${tokenName}) transfer`);
|
const isEusdt = tokenType === 'EUSDT';
|
||||||
|
const marketMakerAddress = isEusdt ? this.eusdtMarketMakerAddress : this.fusdtMarketMakerAddress;
|
||||||
|
const tokenName = isEusdt ? '积分股' : '积分值';
|
||||||
|
|
||||||
|
this.logger.log(`[MM-TRANSFER] Starting ${tokenType} (${tokenName}) Market Maker transfer`);
|
||||||
this.logger.log(`[MM-TRANSFER] Chain: ${chainType}`);
|
this.logger.log(`[MM-TRANSFER] Chain: ${chainType}`);
|
||||||
this.logger.log(`[MM-TRANSFER] From: ${this.marketMakerAddress}`);
|
this.logger.log(`[MM-TRANSFER] From: ${marketMakerAddress}`);
|
||||||
this.logger.log(`[MM-TRANSFER] To: ${toAddress}`);
|
this.logger.log(`[MM-TRANSFER] To: ${toAddress}`);
|
||||||
this.logger.log(`[MM-TRANSFER] Amount: ${amount} ${tokenType}`);
|
this.logger.log(`[MM-TRANSFER] Amount: ${amount} ${tokenType}`);
|
||||||
|
|
||||||
|
|
@ -622,14 +656,23 @@ export class Erc20TransferService {
|
||||||
return { success: false, error };
|
return { success: false, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.mpcSigningClient || !this.mpcSigningClient.isMarketMakerConfigured()) {
|
// 检查对应钱包是否配置
|
||||||
const error = 'Market Maker MPC signing not configured';
|
if (isEusdt) {
|
||||||
this.logger.error(`[MM-TRANSFER] ${error}`);
|
if (!this.mpcSigningClient || !this.mpcSigningClient.isEusdtMarketMakerConfigured()) {
|
||||||
return { success: false, error };
|
const error = 'eUSDT Market Maker MPC signing not configured';
|
||||||
|
this.logger.error(`[MM-TRANSFER] ${error}`);
|
||||||
|
return { success: false, error };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!this.mpcSigningClient || !this.mpcSigningClient.isFusdtMarketMakerConfigured()) {
|
||||||
|
const error = 'fUSDT Market Maker MPC signing not configured';
|
||||||
|
this.logger.error(`[MM-TRANSFER] ${error}`);
|
||||||
|
return { success: false, error };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.marketMakerAddress) {
|
if (!marketMakerAddress) {
|
||||||
const error = 'Market Maker wallet address not configured';
|
const error = `${tokenType} Market Maker wallet address not configured`;
|
||||||
this.logger.error(`[MM-TRANSFER] ${error}`);
|
this.logger.error(`[MM-TRANSFER] ${error}`);
|
||||||
return { success: false, error };
|
return { success: false, error };
|
||||||
}
|
}
|
||||||
|
|
@ -655,7 +698,7 @@ export class Erc20TransferService {
|
||||||
this.logger.log(`[MM-TRANSFER] Amount in wei: ${amountInWei.toString()}`);
|
this.logger.log(`[MM-TRANSFER] Amount in wei: ${amountInWei.toString()}`);
|
||||||
|
|
||||||
// 检查余额
|
// 检查余额
|
||||||
const balance = await contract.balanceOf(this.marketMakerAddress);
|
const balance = await contract.balanceOf(marketMakerAddress);
|
||||||
this.logger.log(`[MM-TRANSFER] Market Maker balance: ${formatUnits(balance, decimals)} ${tokenType}`);
|
this.logger.log(`[MM-TRANSFER] Market Maker balance: ${formatUnits(balance, decimals)} ${tokenType}`);
|
||||||
|
|
||||||
if (balance < amountInWei) {
|
if (balance < amountInWei) {
|
||||||
|
|
@ -666,7 +709,7 @@ export class Erc20TransferService {
|
||||||
|
|
||||||
// 构建交易
|
// 构建交易
|
||||||
this.logger.log(`[MM-TRANSFER] Building transaction...`);
|
this.logger.log(`[MM-TRANSFER] Building transaction...`);
|
||||||
const nonce = await provider.getTransactionCount(this.marketMakerAddress);
|
const nonce = await provider.getTransactionCount(marketMakerAddress);
|
||||||
const feeData = await provider.getFeeData();
|
const feeData = await provider.getFeeData();
|
||||||
|
|
||||||
// ERC20 transfer 的 calldata
|
// ERC20 transfer 的 calldata
|
||||||
|
|
@ -674,7 +717,7 @@ export class Erc20TransferService {
|
||||||
|
|
||||||
// 估算 gas
|
// 估算 gas
|
||||||
const gasEstimate = await provider.estimateGas({
|
const gasEstimate = await provider.estimateGas({
|
||||||
from: this.marketMakerAddress,
|
from: marketMakerAddress,
|
||||||
to: contractAddress,
|
to: contractAddress,
|
||||||
data: transferData,
|
data: transferData,
|
||||||
});
|
});
|
||||||
|
|
@ -715,9 +758,11 @@ export class Erc20TransferService {
|
||||||
const unsignedTxHash = tx.unsignedHash;
|
const unsignedTxHash = tx.unsignedHash;
|
||||||
this.logger.log(`[MM-TRANSFER] Unsigned tx hash: ${unsignedTxHash}`);
|
this.logger.log(`[MM-TRANSFER] Unsigned tx hash: ${unsignedTxHash}`);
|
||||||
|
|
||||||
// 使用做市商 MPC 钱包签名
|
// 使用对应的做市商 MPC 钱包签名
|
||||||
this.logger.log(`[MM-TRANSFER] Requesting Market Maker MPC signature...`);
|
this.logger.log(`[MM-TRANSFER] Requesting ${tokenType} Market Maker MPC signature...`);
|
||||||
const signatureHex = await this.mpcSigningClient.signMessageAsMarketMaker(unsignedTxHash);
|
const signatureHex = isEusdt
|
||||||
|
? await this.mpcSigningClient!.signMessageAsEusdtMarketMaker(unsignedTxHash)
|
||||||
|
: await this.mpcSigningClient!.signMessageAsFusdtMarketMaker(unsignedTxHash);
|
||||||
this.logger.log(`[MM-TRANSFER] MPC signature obtained: ${signatureHex.slice(0, 20)}...`);
|
this.logger.log(`[MM-TRANSFER] MPC signature obtained: ${signatureHex.slice(0, 20)}...`);
|
||||||
|
|
||||||
// 解析签名
|
// 解析签名
|
||||||
|
|
@ -733,7 +778,7 @@ export class Erc20TransferService {
|
||||||
const testSig = Signature.from({ r, s, yParity });
|
const testSig = Signature.from({ r, s, yParity });
|
||||||
const recoveredAddress = recoverAddress(unsignedTxHash, testSig);
|
const recoveredAddress = recoverAddress(unsignedTxHash, testSig);
|
||||||
|
|
||||||
if (recoveredAddress.toLowerCase() === this.marketMakerAddress.toLowerCase()) {
|
if (recoveredAddress.toLowerCase() === marketMakerAddress.toLowerCase()) {
|
||||||
this.logger.log(`[MM-TRANSFER] Found correct yParity: ${yParity}`);
|
this.logger.log(`[MM-TRANSFER] Found correct yParity: ${yParity}`);
|
||||||
signature = testSig;
|
signature = testSig;
|
||||||
break;
|
break;
|
||||||
|
|
@ -786,25 +831,50 @@ export class Erc20TransferService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取做市商指定代币余额
|
* 获取 eUSDT 做市商代币余额
|
||||||
*/
|
*/
|
||||||
async getMarketMakerTokenBalance(chainType: ChainTypeEnum, tokenType: TokenType): Promise<string> {
|
async getEusdtMarketMakerTokenBalance(chainType: ChainTypeEnum): Promise<string> {
|
||||||
const provider = this.providers.get(chainType);
|
const provider = this.providers.get(chainType);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
throw new Error(`Provider not configured for chain: ${chainType}`);
|
throw new Error(`Provider not configured for chain: ${chainType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.marketMakerAddress) {
|
if (!this.eusdtMarketMakerAddress) {
|
||||||
throw new Error('Market Maker wallet address not configured');
|
throw new Error('eUSDT Market Maker wallet address not configured');
|
||||||
}
|
}
|
||||||
|
|
||||||
const contractAddress = this.getTokenContract(chainType, tokenType);
|
const contractAddress = this.getTokenContract(chainType, 'EUSDT');
|
||||||
if (!contractAddress) {
|
if (!contractAddress) {
|
||||||
throw new Error(`Token ${tokenType} not configured for chain ${chainType}`);
|
throw new Error(`eUSDT not configured for chain ${chainType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contract = new Contract(contractAddress, ERC20_TRANSFER_ABI, provider);
|
const contract = new Contract(contractAddress, ERC20_TRANSFER_ABI, provider);
|
||||||
const balance = await contract.balanceOf(this.marketMakerAddress);
|
const balance = await contract.balanceOf(this.eusdtMarketMakerAddress);
|
||||||
|
const decimals = await contract.decimals();
|
||||||
|
|
||||||
|
return formatUnits(balance, decimals);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 fUSDT 做市商代币余额
|
||||||
|
*/
|
||||||
|
async getFusdtMarketMakerTokenBalance(chainType: ChainTypeEnum): Promise<string> {
|
||||||
|
const provider = this.providers.get(chainType);
|
||||||
|
if (!provider) {
|
||||||
|
throw new Error(`Provider not configured for chain: ${chainType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.fusdtMarketMakerAddress) {
|
||||||
|
throw new Error('fUSDT Market Maker wallet address not configured');
|
||||||
|
}
|
||||||
|
|
||||||
|
const contractAddress = this.getTokenContract(chainType, 'FUSDT');
|
||||||
|
if (!contractAddress) {
|
||||||
|
throw new Error(`fUSDT not configured for chain ${chainType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const contract = new Contract(contractAddress, ERC20_TRANSFER_ABI, provider);
|
||||||
|
const balance = await contract.balanceOf(this.fusdtMarketMakerAddress);
|
||||||
const decimals = await contract.decimals();
|
const decimals = await contract.decimals();
|
||||||
|
|
||||||
return formatUnits(balance, decimals);
|
return formatUnits(balance, decimals);
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,12 @@ export class MpcSigningClient implements OnModuleInit {
|
||||||
// C2C Bot 热钱包
|
// C2C Bot 热钱包
|
||||||
private readonly hotWalletUsername: string;
|
private readonly hotWalletUsername: string;
|
||||||
private readonly hotWalletAddress: string;
|
private readonly hotWalletAddress: string;
|
||||||
// 做市商 MPC 钱包
|
// eUSDT (积分股) 做市商钱包
|
||||||
private readonly marketMakerUsername: string;
|
private readonly eusdtMarketMakerUsername: string;
|
||||||
private readonly marketMakerAddress: string;
|
private readonly eusdtMarketMakerAddress: string;
|
||||||
|
// fUSDT (积分值) 做市商钱包
|
||||||
|
private readonly fusdtMarketMakerUsername: string;
|
||||||
|
private readonly fusdtMarketMakerAddress: string;
|
||||||
private readonly signingTimeoutMs: number = 300000; // 5 minutes
|
private readonly signingTimeoutMs: number = 300000; // 5 minutes
|
||||||
|
|
||||||
// 待处理的签名请求回调 Map<sessionId, { resolve, reject, timeout }>
|
// 待处理的签名请求回调 Map<sessionId, { resolve, reject, timeout }>
|
||||||
|
|
@ -62,9 +65,12 @@ export class MpcSigningClient implements OnModuleInit {
|
||||||
// C2C Bot 热钱包配置
|
// C2C Bot 热钱包配置
|
||||||
this.hotWalletUsername = this.configService.get<string>('HOT_WALLET_USERNAME', '');
|
this.hotWalletUsername = this.configService.get<string>('HOT_WALLET_USERNAME', '');
|
||||||
this.hotWalletAddress = this.configService.get<string>('HOT_WALLET_ADDRESS', '');
|
this.hotWalletAddress = this.configService.get<string>('HOT_WALLET_ADDRESS', '');
|
||||||
// 做市商 MPC 钱包配置
|
// eUSDT (积分股) 做市商钱包配置
|
||||||
this.marketMakerUsername = this.configService.get<string>('MARKET_MAKER_MPC_USERNAME', '');
|
this.eusdtMarketMakerUsername = this.configService.get<string>('EUSDT_MARKET_MAKER_USERNAME', '');
|
||||||
this.marketMakerAddress = this.configService.get<string>('MARKET_MAKER_WALLET_ADDRESS', '');
|
this.eusdtMarketMakerAddress = this.configService.get<string>('EUSDT_MARKET_MAKER_ADDRESS', '');
|
||||||
|
// fUSDT (积分值) 做市商钱包配置
|
||||||
|
this.fusdtMarketMakerUsername = this.configService.get<string>('FUSDT_MARKET_MAKER_USERNAME', '');
|
||||||
|
this.fusdtMarketMakerAddress = this.configService.get<string>('FUSDT_MARKET_MAKER_ADDRESS', '');
|
||||||
|
|
||||||
if (!this.hotWalletUsername) {
|
if (!this.hotWalletUsername) {
|
||||||
this.logger.warn('[INIT] HOT_WALLET_USERNAME not configured (C2C Bot disabled)');
|
this.logger.warn('[INIT] HOT_WALLET_USERNAME not configured (C2C Bot disabled)');
|
||||||
|
|
@ -72,15 +78,16 @@ export class MpcSigningClient implements OnModuleInit {
|
||||||
if (!this.hotWalletAddress) {
|
if (!this.hotWalletAddress) {
|
||||||
this.logger.warn('[INIT] HOT_WALLET_ADDRESS not configured (C2C Bot disabled)');
|
this.logger.warn('[INIT] HOT_WALLET_ADDRESS not configured (C2C Bot disabled)');
|
||||||
}
|
}
|
||||||
if (!this.marketMakerUsername) {
|
if (!this.eusdtMarketMakerUsername || !this.eusdtMarketMakerAddress) {
|
||||||
this.logger.warn('[INIT] MARKET_MAKER_MPC_USERNAME not configured (Market Maker signing disabled)');
|
this.logger.warn('[INIT] eUSDT Market Maker not configured');
|
||||||
}
|
}
|
||||||
if (!this.marketMakerAddress) {
|
if (!this.fusdtMarketMakerUsername || !this.fusdtMarketMakerAddress) {
|
||||||
this.logger.warn('[INIT] MARKET_MAKER_WALLET_ADDRESS not configured (Market Maker disabled)');
|
this.logger.warn('[INIT] fUSDT Market Maker not configured');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.log(`[INIT] C2C Bot Wallet: ${this.hotWalletAddress || '(not configured)'}`);
|
this.logger.log(`[INIT] C2C Bot Wallet: ${this.hotWalletAddress || '(not configured)'}`);
|
||||||
this.logger.log(`[INIT] Market Maker Wallet: ${this.marketMakerAddress || '(not configured)'}`);
|
this.logger.log(`[INIT] eUSDT Market Maker: ${this.eusdtMarketMakerAddress || '(not configured)'}`);
|
||||||
|
this.logger.log(`[INIT] fUSDT Market Maker: ${this.fusdtMarketMakerAddress || '(not configured)'}`);
|
||||||
this.logger.log(`[INIT] Using Kafka event-driven signing`);
|
this.logger.log(`[INIT] Using Kafka event-driven signing`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,10 +106,17 @@ export class MpcSigningClient implements OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查做市商钱包是否已配置
|
* 检查 eUSDT 做市商钱包是否已配置
|
||||||
*/
|
*/
|
||||||
isMarketMakerConfigured(): boolean {
|
isEusdtMarketMakerConfigured(): boolean {
|
||||||
return !!this.marketMakerUsername && !!this.marketMakerAddress;
|
return !!this.eusdtMarketMakerUsername && !!this.eusdtMarketMakerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 fUSDT 做市商钱包是否已配置
|
||||||
|
*/
|
||||||
|
isFusdtMarketMakerConfigured(): boolean {
|
||||||
|
return !!this.fusdtMarketMakerUsername && !!this.fusdtMarketMakerAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -120,17 +134,31 @@ export class MpcSigningClient implements OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取做市商钱包地址
|
* 获取 eUSDT 做市商钱包地址
|
||||||
*/
|
*/
|
||||||
getMarketMakerAddress(): string {
|
getEusdtMarketMakerAddress(): string {
|
||||||
return this.marketMakerAddress;
|
return this.eusdtMarketMakerAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取做市商 MPC 用户名
|
* 获取 eUSDT 做市商 MPC 用户名
|
||||||
*/
|
*/
|
||||||
getMarketMakerUsername(): string {
|
getEusdtMarketMakerUsername(): string {
|
||||||
return this.marketMakerUsername;
|
return this.eusdtMarketMakerUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 fUSDT 做市商钱包地址
|
||||||
|
*/
|
||||||
|
getFusdtMarketMakerAddress(): string {
|
||||||
|
return this.fusdtMarketMakerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 fUSDT 做市商 MPC 用户名
|
||||||
|
*/
|
||||||
|
getFusdtMarketMakerUsername(): string {
|
||||||
|
return this.fusdtMarketMakerUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -147,16 +175,29 @@ export class MpcSigningClient implements OnModuleInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用做市商钱包签名消息
|
* 使用 eUSDT 做市商钱包签名消息
|
||||||
*
|
*
|
||||||
* @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
|
* @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
|
||||||
* @returns 签名结果 (hex string)
|
* @returns 签名结果 (hex string)
|
||||||
*/
|
*/
|
||||||
async signMessageAsMarketMaker(messageHash: string): Promise<string> {
|
async signMessageAsEusdtMarketMaker(messageHash: string): Promise<string> {
|
||||||
if (!this.marketMakerUsername) {
|
if (!this.eusdtMarketMakerUsername) {
|
||||||
throw new Error('Market maker MPC username not configured');
|
throw new Error('eUSDT Market Maker MPC username not configured');
|
||||||
}
|
}
|
||||||
return this.signMessageWithUsername(this.marketMakerUsername, messageHash);
|
return this.signMessageWithUsername(this.eusdtMarketMakerUsername, messageHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 fUSDT 做市商钱包签名消息
|
||||||
|
*
|
||||||
|
* @param messageHash 要签名的消息哈希 (hex string with 0x prefix)
|
||||||
|
* @returns 签名结果 (hex string)
|
||||||
|
*/
|
||||||
|
async signMessageAsFusdtMarketMaker(messageHash: string): Promise<string> {
|
||||||
|
if (!this.fusdtMarketMakerUsername) {
|
||||||
|
throw new Error('fUSDT Market Maker MPC username not configured');
|
||||||
|
}
|
||||||
|
return this.signMessageWithUsername(this.fusdtMarketMakerUsername, messageHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue