feat(market-maker): 积分股(eUSDT)和积分值(fUSDT)使用独立 MPC 钱包
- Prisma: MarketMakerConfig 新增 eusdt_wallet_address 字段 - 后端: 初始化/更新配置时读取 EUSDT_MARKET_MAKER_ADDRESS 环境变量 - 后端: getConfig API 返回 eusdtWalletAddress - 前端: 积分股充值弹窗使用 eusdtWalletAddress (不再共用 kavaWalletAddress) - 前端: 积分值充值弹窗继续使用 kavaWalletAddress (fUSDT 钱包) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
38ee808239
commit
ebe7123583
|
|
@ -0,0 +1,2 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "MarketMakerConfig" ADD COLUMN "eusdt_wallet_address" VARCHAR(42);
|
||||
|
|
@ -471,8 +471,10 @@ model MarketMakerConfig {
|
|||
accountSequence String @unique @map("account_sequence") // 做市商专用交易账户
|
||||
|
||||
// ============ 区块链钱包配置(MPC)============
|
||||
// 做市商 Kava 链钱包地址(MPC 钱包,用于充值监控和提现)
|
||||
kavaWalletAddress String? @map("kava_wallet_address") @db.VarChar(42)
|
||||
// fUSDT (积分值) 做市商 Kava 链钱包地址(MPC 钱包,用于充值监控和提现)
|
||||
kavaWalletAddress String? @map("kava_wallet_address") @db.VarChar(42)
|
||||
// eUSDT (积分股) 做市商 Kava 链钱包地址(MPC 钱包,用于积分股充值监控和提现)
|
||||
eusdtWalletAddress String? @map("eusdt_wallet_address") @db.VarChar(42)
|
||||
// MPC 用户名(用于签名提现交易)
|
||||
mpcUsername String? @map("mpc_username") @db.VarChar(100)
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ class UpdateConfigDto {
|
|||
@IsOptional()
|
||||
@IsString()
|
||||
kavaWalletAddress?: string;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
eusdtWalletAddress?: string;
|
||||
}
|
||||
|
||||
class UpdateMakerConfigDto {
|
||||
|
|
@ -214,6 +218,7 @@ export class MarketMakerController {
|
|||
discountRate: config.discountRate.toString(),
|
||||
isActive: config.isActive,
|
||||
kavaWalletAddress: config.kavaWalletAddress,
|
||||
eusdtWalletAddress: config.eusdtWalletAddress,
|
||||
},
|
||||
runningStatus,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export interface MarketMakerConfig {
|
|||
discountRate: Decimal;
|
||||
isActive: boolean;
|
||||
kavaWalletAddress: string | null;
|
||||
eusdtWalletAddress: string | null;
|
||||
}
|
||||
|
||||
export enum LedgerType {
|
||||
|
|
@ -106,6 +107,7 @@ export class MarketMakerService {
|
|||
discountRate: new Decimal(config.discountRate.toString()),
|
||||
isActive: config.isActive,
|
||||
kavaWalletAddress: config.kavaWalletAddress,
|
||||
eusdtWalletAddress: config.eusdtWalletAddress,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -153,16 +155,22 @@ export class MarketMakerService {
|
|||
const existing = await this.getConfig(name);
|
||||
if (existing) {
|
||||
// 如果存在但钱包地址为空,尝试从环境变量更新
|
||||
const updateData: any = {};
|
||||
if (!existing.kavaWalletAddress) {
|
||||
const kavaWalletAddress = this.configService.get<string>('FUSDT_MARKET_MAKER_ADDRESS');
|
||||
if (kavaWalletAddress) {
|
||||
await this.prisma.marketMakerConfig.update({
|
||||
where: { name },
|
||||
data: { kavaWalletAddress },
|
||||
});
|
||||
this.logger.log(`Market maker ${name} wallet address updated from env: ${kavaWalletAddress}`);
|
||||
return this.getConfig(name) as Promise<MarketMakerConfig>;
|
||||
}
|
||||
if (kavaWalletAddress) updateData.kavaWalletAddress = kavaWalletAddress;
|
||||
}
|
||||
if (!existing.eusdtWalletAddress) {
|
||||
const eusdtWalletAddress = this.configService.get<string>('EUSDT_MARKET_MAKER_ADDRESS');
|
||||
if (eusdtWalletAddress) updateData.eusdtWalletAddress = eusdtWalletAddress;
|
||||
}
|
||||
if (Object.keys(updateData).length > 0) {
|
||||
await this.prisma.marketMakerConfig.update({
|
||||
where: { name },
|
||||
data: updateData,
|
||||
});
|
||||
this.logger.log(`Market maker ${name} wallet addresses updated from env: ${JSON.stringify(updateData)}`);
|
||||
return this.getConfig(name) as Promise<MarketMakerConfig>;
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
|
|
@ -176,6 +184,7 @@ export class MarketMakerService {
|
|||
|
||||
// 从环境变量读取做市商钱包地址
|
||||
const kavaWalletAddress = this.configService.get<string>('FUSDT_MARKET_MAKER_ADDRESS') || null;
|
||||
const eusdtWalletAddress = this.configService.get<string>('EUSDT_MARKET_MAKER_ADDRESS') || null;
|
||||
|
||||
// 创建做市商配置
|
||||
const config = await this.prisma.marketMakerConfig.create({
|
||||
|
|
@ -187,10 +196,11 @@ export class MarketMakerService {
|
|||
minIntervalMs: params.minIntervalMs || 1000,
|
||||
maxIntervalMs: params.maxIntervalMs || 1000,
|
||||
kavaWalletAddress,
|
||||
eusdtWalletAddress,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log(`Market maker initialized: ${name}, account: ${params.accountSequence}, wallet: ${kavaWalletAddress || 'not configured'}`);
|
||||
this.logger.log(`Market maker initialized: ${name}, account: ${params.accountSequence}, fUSDT wallet: ${kavaWalletAddress || 'not configured'}, eUSDT wallet: ${eusdtWalletAddress || 'not configured'}`);
|
||||
|
||||
return this.getConfig(name) as Promise<MarketMakerConfig>;
|
||||
}
|
||||
|
|
@ -761,6 +771,7 @@ export class MarketMakerService {
|
|||
priceStrategy?: string;
|
||||
discountRate?: number;
|
||||
kavaWalletAddress?: string;
|
||||
eusdtWalletAddress?: string;
|
||||
},
|
||||
): Promise<MarketMakerConfig | null> {
|
||||
const config = await this.getConfig(name);
|
||||
|
|
|
|||
|
|
@ -447,21 +447,21 @@ export default function MarketMakerPage() {
|
|||
<div className="text-sm text-muted-foreground text-center">
|
||||
向以下地址转入 <strong>eUSDT</strong> (积分股代币)
|
||||
</div>
|
||||
{config.kavaWalletAddress ? (
|
||||
{config.eusdtWalletAddress ? (
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<div className="p-4 bg-white rounded-lg">
|
||||
<QRCodeSVG value={config.kavaWalletAddress} size={180} />
|
||||
<QRCodeSVG value={config.eusdtWalletAddress} size={180} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Label className="text-xs text-muted-foreground">钱包地址 (Kava EVM)</Label>
|
||||
<Label className="text-xs text-muted-foreground">eUSDT 钱包地址 (Kava EVM)</Label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<code className="flex-1 text-xs bg-muted p-2 rounded break-all">
|
||||
{config.kavaWalletAddress}
|
||||
{config.eusdtWalletAddress}
|
||||
</code>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => handleCopyAddress(config.kavaWalletAddress!)}
|
||||
onClick={() => handleCopyAddress(config.eusdtWalletAddress!)}
|
||||
>
|
||||
{copiedAddress ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
|
||||
</Button>
|
||||
|
|
@ -476,10 +476,11 @@ export default function MarketMakerPage() {
|
|||
<div className="space-y-4">
|
||||
<div className="text-center text-muted-foreground py-2">
|
||||
<AlertCircle className="h-6 w-6 mx-auto mb-2 text-yellow-500" />
|
||||
<p className="text-sm">做市商钱包地址未配置</p>
|
||||
<p className="text-sm">eUSDT 做市商钱包地址未配置</p>
|
||||
<p className="text-xs mt-1">请在 .env 中设置 EUSDT_MARKET_MAKER_ADDRESS</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-xs">配置钱包地址 (Kava EVM)</Label>
|
||||
<Label className="text-xs">配置 eUSDT 钱包地址 (Kava EVM)</Label>
|
||||
<Input
|
||||
value={walletAddressInput}
|
||||
onChange={(e) => setWalletAddressInput(e.target.value)}
|
||||
|
|
@ -490,7 +491,7 @@ export default function MarketMakerPage() {
|
|||
<Button
|
||||
className="w-full"
|
||||
onClick={() => {
|
||||
updateConfigMutation.mutate({ kavaWalletAddress: walletAddressInput });
|
||||
updateConfigMutation.mutate({ eusdtWalletAddress: walletAddressInput });
|
||||
setWalletAddressInput('');
|
||||
}}
|
||||
disabled={updateConfigMutation.isPending || !walletAddressInput || !walletAddressInput.startsWith('0x')}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ export interface MarketMakerConfig {
|
|||
refreshIntervalMs?: number;
|
||||
lastRefreshAt?: string;
|
||||
kavaWalletAddress?: string;
|
||||
eusdtWalletAddress?: string;
|
||||
}
|
||||
|
||||
export interface MarketMakerOrder {
|
||||
|
|
@ -143,6 +144,7 @@ export const marketMakerApi = {
|
|||
priceStrategy?: string;
|
||||
discountRate?: number;
|
||||
kavaWalletAddress?: string;
|
||||
eusdtWalletAddress?: string;
|
||||
}): Promise<{ success: boolean; message: string }> => {
|
||||
const response = await tradingClient.post(`/admin/market-maker/${name}/config`, data);
|
||||
return response.data;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export function useUpdateMarketMakerConfig() {
|
|||
priceStrategy?: string;
|
||||
discountRate?: number;
|
||||
kavaWalletAddress?: string;
|
||||
eusdtWalletAddress?: string;
|
||||
}) => marketMakerApi.updateConfig(MARKET_MAKER_NAME, data),
|
||||
onSuccess: (data) => {
|
||||
toast({ title: '成功', description: data.message });
|
||||
|
|
|
|||
Loading…
Reference in New Issue