feat: split share pool into A (100亿) and B (200万) accounts
Backend changes: - mining-wallet-service: Split SHARE_POOL into SHARE_POOL_A (100亿, for burning) and SHARE_POOL_B (200万, for mining distribution) - Add /pool-accounts/share-pool-balance API endpoint to get total balance - Update pool initialization logic and seed data - Fix Kong routing for mining-wallet-service (strip_path: true) - Fix Kong routing for trading-service (strip_path: true) Constant updates (100.02亿 = 10,002,000,000): - mining-service: TOTAL_SHARES - trading-service: TOTAL_SHARES, trading config defaults - trading-service seed: initial green points = 5760 Frontend changes: - Add sharePoolBalanceProvider to fetch pool balance from mining-wallet-service - Update contribution page to display real-time share pool balance (A + B) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a1508b208e
commit
40869ef00f
|
|
@ -357,18 +357,19 @@ services:
|
|||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Mining Wallet Service 2.0 - 挖矿钱包服务
|
||||
# 前端路径: /api/v2/mining-wallet/... -> 后端路径: /api/v2/...
|
||||
# ---------------------------------------------------------------------------
|
||||
- name: mining-wallet-service
|
||||
url: http://192.168.1.111:3025
|
||||
url: http://192.168.1.111:3025/api/v2
|
||||
routes:
|
||||
- name: mining-wallet-api
|
||||
paths:
|
||||
- /api/v2/mining-wallet
|
||||
strip_path: false
|
||||
strip_path: true
|
||||
- name: mining-wallet-health
|
||||
paths:
|
||||
- /api/v2/mining-wallet/health
|
||||
strip_path: false
|
||||
strip_path: true
|
||||
|
||||
# =============================================================================
|
||||
# Plugins - 全局插件配置
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ datasource db {
|
|||
// 挖矿全局配置
|
||||
model MiningConfig {
|
||||
id String @id @default(uuid())
|
||||
totalShares Decimal @db.Decimal(30, 8) // 总积分股数量 (100.02B)
|
||||
totalShares Decimal @db.Decimal(30, 8) // 总积分股数量 (100.02亿)
|
||||
distributionPool Decimal @db.Decimal(30, 8) // 分配池 (200M)
|
||||
remainingDistribution Decimal @db.Decimal(30, 8) // 剩余可分配
|
||||
halvingPeriodYears Int @default(2) // 减半周期(年)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ async function main() {
|
|||
const now = new Date();
|
||||
|
||||
// 常量
|
||||
const TOTAL_SHARES = new Decimal('100020000000'); // 100.02B
|
||||
const TOTAL_SHARES = new Decimal('10002000000'); // 100.02亿
|
||||
const DISTRIBUTION_POOL = new Decimal('2000000'); // 200万
|
||||
const ERA1_DISTRIBUTION = new Decimal('1000000'); // 100万(第一个两年)
|
||||
const BURN_TARGET = new Decimal('10000000000'); // 100亿
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import { Price } from '../value-objects/price.vo';
|
|||
* 挖矿计算领域服务
|
||||
*/
|
||||
export class MiningCalculatorService {
|
||||
// 总积分股数量: 100.02B
|
||||
static readonly TOTAL_SHARES = new ShareAmount('100020000000');
|
||||
// 总积分股数量: 100.02亿 (SHARE_POOL_A: 100亿 + SHARE_POOL_B: 200万)
|
||||
static readonly TOTAL_SHARES = new ShareAmount('10002000000');
|
||||
|
||||
// 初始分配池: 200M
|
||||
static readonly INITIAL_DISTRIBUTION_POOL = new ShareAmount('200000000');
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ enum SystemAccountType {
|
|||
|
||||
// 池账户类型
|
||||
enum PoolAccountType {
|
||||
SHARE_POOL // 积分股池 - 总股池
|
||||
SHARE_POOL_A // 积分股池A - 初始100亿
|
||||
SHARE_POOL_B // 积分股池B - 初始200万
|
||||
BLACK_HOLE_POOL // 黑洞积分股池 - 销毁池
|
||||
CIRCULATION_POOL // 流通积分股池 - 交易流通池
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,19 +62,28 @@ async function main() {
|
|||
}
|
||||
}
|
||||
|
||||
// 2. 初始化池账户(积分股池、黑洞池、流通池)
|
||||
// 2. 初始化池账户(积分股池A/B、黑洞池、流通池)
|
||||
// 积分股池A: 100亿 (10,000,000,000) - 用于销毁
|
||||
// 积分股池B: 200万 (2,000,000) - 用于挖矿分配
|
||||
// 总计: 100.02亿 (10,002,000,000)
|
||||
const poolAccounts = [
|
||||
{
|
||||
poolType: 'SHARE_POOL',
|
||||
name: '积分股池',
|
||||
balance: new Decimal('100000000'), // 1亿初始发行量
|
||||
description: '挖矿奖励的来源池,总发行量',
|
||||
poolType: 'SHARE_POOL_A',
|
||||
name: '积分股池A',
|
||||
balance: new Decimal('10000000000'), // 100亿初始发行量
|
||||
description: '销毁池来源,初始100亿',
|
||||
},
|
||||
{
|
||||
poolType: 'SHARE_POOL_B',
|
||||
name: '积分股池B',
|
||||
balance: new Decimal('2000000'), // 200万初始发行量
|
||||
description: '挖矿分配池,初始200万',
|
||||
},
|
||||
{
|
||||
poolType: 'BLACK_HOLE_POOL',
|
||||
name: '黑洞池',
|
||||
balance: new Decimal('0'),
|
||||
targetBurn: new Decimal('50000000'), // 目标销毁5000万
|
||||
targetBurn: new Decimal('10000000000'), // 目标销毁100亿
|
||||
description: '销毁的积分股,用于减少流通量',
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import { PoolAccountType, TransactionType } from '@prisma/client';
|
|||
import Decimal from 'decimal.js';
|
||||
|
||||
class InitializePoolsDto {
|
||||
sharePool: { name: string; initialBalance?: string };
|
||||
sharePoolA: { name: string; initialBalance?: string };
|
||||
sharePoolB: { name: string; initialBalance?: string };
|
||||
blackHolePool: { name: string; targetBurn: string };
|
||||
circulationPool: { name: string; initialBalance?: string };
|
||||
}
|
||||
|
|
@ -78,10 +79,16 @@ export class PoolAccountController {
|
|||
@ApiResponse({ status: 201, description: '池账户初始化成功' })
|
||||
async initialize(@Body() dto: InitializePoolsDto) {
|
||||
return this.poolAccountService.initializePools({
|
||||
sharePool: {
|
||||
name: dto.sharePool.name,
|
||||
initialBalance: dto.sharePool.initialBalance
|
||||
? new Decimal(dto.sharePool.initialBalance)
|
||||
sharePoolA: {
|
||||
name: dto.sharePoolA.name,
|
||||
initialBalance: dto.sharePoolA.initialBalance
|
||||
? new Decimal(dto.sharePoolA.initialBalance)
|
||||
: undefined,
|
||||
},
|
||||
sharePoolB: {
|
||||
name: dto.sharePoolB.name,
|
||||
initialBalance: dto.sharePoolB.initialBalance
|
||||
? new Decimal(dto.sharePoolB.initialBalance)
|
||||
: undefined,
|
||||
},
|
||||
blackHolePool: {
|
||||
|
|
@ -97,6 +104,14 @@ export class PoolAccountController {
|
|||
});
|
||||
}
|
||||
|
||||
@Get('share-pool-balance')
|
||||
@Public()
|
||||
@ApiOperation({ summary: '获取积分股池总余量' })
|
||||
@ApiResponse({ status: 200, description: '积分股池A+B的总余量' })
|
||||
async getSharePoolTotalBalance() {
|
||||
return this.poolAccountService.getSharePoolTotalBalance();
|
||||
}
|
||||
|
||||
@Post('burn')
|
||||
@AdminOnly()
|
||||
@ApiOperation({ summary: '销毁到黑洞池' })
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ import Decimal from 'decimal.js';
|
|||
import { DomainException } from '../../shared/filters/domain-exception.filter';
|
||||
|
||||
export interface InitializePoolsInput {
|
||||
sharePool: {
|
||||
sharePoolA: {
|
||||
name: string;
|
||||
initialBalance?: Decimal;
|
||||
};
|
||||
sharePoolB: {
|
||||
name: string;
|
||||
initialBalance?: Decimal;
|
||||
};
|
||||
|
|
@ -30,27 +34,45 @@ export class PoolAccountService {
|
|||
) {}
|
||||
|
||||
/**
|
||||
* 初始化三大池账户
|
||||
* 初始化四大池账户
|
||||
*/
|
||||
async initializePools(input: InitializePoolsInput): Promise<PoolAccount[]> {
|
||||
const pools: PoolAccount[] = [];
|
||||
|
||||
// 积分股池
|
||||
const sharePool = await this.poolAccountRepo.create({
|
||||
poolType: 'SHARE_POOL',
|
||||
name: input.sharePool.name,
|
||||
// 积分股池A - 初始100亿
|
||||
const sharePoolA = await this.poolAccountRepo.create({
|
||||
poolType: 'SHARE_POOL_A',
|
||||
name: input.sharePoolA.name,
|
||||
});
|
||||
pools.push(sharePool);
|
||||
pools.push(sharePoolA);
|
||||
|
||||
// 如果有初始余额,注入资金
|
||||
if (input.sharePool.initialBalance?.greaterThan(0)) {
|
||||
if (input.sharePoolA.initialBalance?.greaterThan(0)) {
|
||||
await this.poolAccountRepo.updateBalanceWithTransaction(
|
||||
'SHARE_POOL',
|
||||
input.sharePool.initialBalance,
|
||||
'SHARE_POOL_A',
|
||||
input.sharePoolA.initialBalance,
|
||||
{
|
||||
transactionType: 'INITIAL_INJECT',
|
||||
counterpartyType: 'EXTERNAL',
|
||||
memo: `初始注入, 数量${input.sharePool.initialBalance.toFixed(8)}`,
|
||||
memo: `初始注入积分股池A, 数量${input.sharePoolA.initialBalance.toFixed(8)}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// 积分股池B - 初始200万
|
||||
const sharePoolB = await this.poolAccountRepo.create({
|
||||
poolType: 'SHARE_POOL_B',
|
||||
name: input.sharePoolB.name,
|
||||
});
|
||||
pools.push(sharePoolB);
|
||||
|
||||
if (input.sharePoolB.initialBalance?.greaterThan(0)) {
|
||||
await this.poolAccountRepo.updateBalanceWithTransaction(
|
||||
'SHARE_POOL_B',
|
||||
input.sharePoolB.initialBalance,
|
||||
{
|
||||
transactionType: 'INITIAL_INJECT',
|
||||
counterpartyType: 'EXTERNAL',
|
||||
memo: `初始注入积分股池B, 数量${input.sharePoolB.initialBalance.toFixed(8)}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -93,7 +115,8 @@ export class PoolAccountService {
|
|||
type: p.poolType,
|
||||
name: p.name,
|
||||
})),
|
||||
sharePoolInitialBalance: input.sharePool.initialBalance?.toString() || '0',
|
||||
sharePoolAInitialBalance: input.sharePoolA.initialBalance?.toString() || '0',
|
||||
sharePoolBInitialBalance: input.sharePoolB.initialBalance?.toString() || '0',
|
||||
blackHoleTargetBurn: input.blackHolePool.targetBurn.toString(),
|
||||
circulationPoolInitialBalance: input.circulationPool.initialBalance?.toString() || '0',
|
||||
initializedAt: new Date().toISOString(),
|
||||
|
|
@ -106,6 +129,7 @@ export class PoolAccountService {
|
|||
|
||||
/**
|
||||
* 从积分股池分配(挖矿分配)
|
||||
* 挖矿只从 SHARE_POOL_B (200万) 分配
|
||||
*/
|
||||
async distributeMiningReward(
|
||||
toAccountSeq: string,
|
||||
|
|
@ -117,10 +141,12 @@ export class PoolAccountService {
|
|||
referenceId?: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
const sourcePool: PoolAccountType = 'SHARE_POOL_B';
|
||||
|
||||
const memo = `挖矿分配给用户[${toAccountSeq}], 算力占比${miningInfo.contributionRatio.mul(100).toFixed(4)}%, 分钟${miningInfo.miningMinute.toISOString()}`;
|
||||
|
||||
await this.poolAccountRepo.updateBalanceWithTransaction(
|
||||
'SHARE_POOL',
|
||||
sourcePool,
|
||||
amount.negated(),
|
||||
{
|
||||
transactionType: 'MINING_DISTRIBUTE',
|
||||
|
|
@ -139,7 +165,7 @@ export class PoolAccountService {
|
|||
|
||||
await this.outboxRepo.create({
|
||||
aggregateType: 'PoolAccount',
|
||||
aggregateId: 'SHARE_POOL',
|
||||
aggregateId: sourcePool,
|
||||
eventType: 'MINING_DISTRIBUTED',
|
||||
payload: {
|
||||
toAccountSeq,
|
||||
|
|
@ -151,6 +177,30 @@ export class PoolAccountService {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取积分股池总余量 (SHARE_POOL_A + SHARE_POOL_B)
|
||||
*/
|
||||
async getSharePoolTotalBalance(): Promise<{
|
||||
poolA: string;
|
||||
poolB: string;
|
||||
total: string;
|
||||
}> {
|
||||
const [poolA, poolB] = await Promise.all([
|
||||
this.poolAccountRepo.findByType('SHARE_POOL_A'),
|
||||
this.poolAccountRepo.findByType('SHARE_POOL_B'),
|
||||
]);
|
||||
|
||||
const balanceA = poolA ? new Decimal(poolA.balance.toString()) : new Decimal(0);
|
||||
const balanceB = poolB ? new Decimal(poolB.balance.toString()) : new Decimal(0);
|
||||
const total = balanceA.plus(balanceB);
|
||||
|
||||
return {
|
||||
poolA: balanceA.toFixed(8),
|
||||
poolB: balanceB.toFixed(8),
|
||||
total: total.toFixed(8),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户划入流通池(准备卖出)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ datasource db {
|
|||
// 交易全局配置
|
||||
model TradingConfig {
|
||||
id String @id @default(uuid())
|
||||
// 总积分股数量: 100.02B
|
||||
totalShares Decimal @default(100020000000) @map("total_shares") @db.Decimal(30, 8)
|
||||
// 总积分股数量: 100.02亿
|
||||
totalShares Decimal @default(10002000000) @map("total_shares") @db.Decimal(30, 8)
|
||||
// 目标销毁量: 100亿 (4年销毁完)
|
||||
burnTarget Decimal @default(10000000000) @map("burn_target") @db.Decimal(30, 8)
|
||||
// 销毁周期: 4年 (分钟数) 365*4*1440 = 2102400
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ async function main() {
|
|||
if (!existingConfig) {
|
||||
await prisma.tradingConfig.create({
|
||||
data: {
|
||||
totalShares: new Decimal('100020000000'), // 100.02B 总积分股
|
||||
totalShares: new Decimal('10002000000'), // 100.02亿 总积分股
|
||||
burnTarget: new Decimal('10000000000'), // 100亿目标销毁量
|
||||
burnPeriodMinutes: 2102400, // 4年 = 365*4*1440 分钟
|
||||
minuteBurnRate: new Decimal('4756.468797564687'), // 每分钟销毁率
|
||||
|
|
@ -93,17 +93,17 @@ async function main() {
|
|||
console.log('Black hole account already exists');
|
||||
}
|
||||
|
||||
// 4. 初始化积分股池
|
||||
// 4. 初始化积分股池(绿积分池)
|
||||
const existingSharePool = await prisma.sharePool.findFirst();
|
||||
if (!existingSharePool) {
|
||||
await prisma.sharePool.create({
|
||||
data: {
|
||||
greenPoints: new Decimal(0), // 初始绿积分为 0
|
||||
totalInflow: new Decimal(0),
|
||||
greenPoints: new Decimal(5760), // 初始绿积分为 5760
|
||||
totalInflow: new Decimal(5760),
|
||||
totalOutflow: new Decimal(0),
|
||||
},
|
||||
});
|
||||
console.log('Created share pool');
|
||||
console.log('Created share pool with initial green points: 5760');
|
||||
} else {
|
||||
console.log('Share pool already exists');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import { Money } from '../value-objects/money.vo';
|
|||
* 7. 资产每秒增长量 = 用户每天分配的积分股 ÷ 24 ÷ 60 ÷ 60
|
||||
*/
|
||||
export class TradingCalculatorService {
|
||||
// 总积分股数量: 100.02B
|
||||
static readonly TOTAL_SHARES = new Decimal('100020000000');
|
||||
// 总积分股数量: 100.02亿 (SHARE_POOL_A: 100亿 + SHARE_POOL_B: 200万)
|
||||
static readonly TOTAL_SHARES = new Decimal('10002000000');
|
||||
|
||||
// 目标销毁量: 100亿 (4年销毁完)
|
||||
static readonly BURN_TARGET = new Decimal('10000000000');
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export class TradingConfigRepository {
|
|||
|
||||
const record = await this.prisma.tradingConfig.create({
|
||||
data: {
|
||||
totalShares: new Decimal('100020000000'),
|
||||
totalShares: new Decimal('10002000000'), // 100.02亿
|
||||
burnTarget: new Decimal('10000000000'),
|
||||
burnPeriodMinutes: 2102400, // 365 * 4 * 1440
|
||||
minuteBurnRate: new Decimal('4756.468797564687'),
|
||||
|
|
|
|||
|
|
@ -59,4 +59,7 @@ class ApiEndpoints {
|
|||
// Planting Ledger (Kong路由: /api/v2/contribution)
|
||||
static String plantingLedger(String accountSequence) =>
|
||||
'/api/v2/contribution/accounts/$accountSequence/planting-ledger';
|
||||
|
||||
// Mining Wallet Service 2.0 (Kong路由: /api/v2/mining-wallet)
|
||||
static const String sharePoolBalance = '/api/v2/mining-wallet/pool-accounts/share-pool-balance';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@ import '../../../core/constants/app_colors.dart';
|
|||
import '../../../core/router/routes.dart';
|
||||
import '../../../core/utils/format_utils.dart';
|
||||
import '../../../domain/entities/contribution.dart';
|
||||
import '../../../domain/entities/market_overview.dart';
|
||||
import '../../providers/user_providers.dart';
|
||||
import '../../providers/contribution_providers.dart';
|
||||
import '../../providers/trading_providers.dart';
|
||||
import '../../widgets/shimmer_loading.dart';
|
||||
|
||||
class ContributionPage extends ConsumerWidget {
|
||||
|
|
@ -30,8 +28,8 @@ class ContributionPage extends ConsumerWidget {
|
|||
// 获取预估收益
|
||||
final estimatedEarnings = ref.watch(estimatedEarningsProvider(accountSequence));
|
||||
final statsAsync = ref.watch(contributionStatsProvider);
|
||||
// 获取市场概览(积分股池余量)
|
||||
final marketAsync = ref.watch(marketOverviewProvider);
|
||||
// 获取积分股池余量
|
||||
final sharePoolAsync = ref.watch(sharePoolBalanceProvider);
|
||||
|
||||
// Extract loading state and data from AsyncValue
|
||||
final isLoading = contributionAsync.isLoading;
|
||||
|
|
@ -39,8 +37,8 @@ class ContributionPage extends ConsumerWidget {
|
|||
final hasError = contributionAsync.hasError;
|
||||
final error = contributionAsync.error;
|
||||
final isStatsLoading = statsAsync.isLoading;
|
||||
final isMarketLoading = marketAsync.isLoading;
|
||||
final market = marketAsync.valueOrNull;
|
||||
final isSharePoolLoading = sharePoolAsync.isLoading;
|
||||
final sharePoolBalance = sharePoolAsync.valueOrNull;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFFF5F5F5),
|
||||
|
|
@ -50,7 +48,7 @@ class ContributionPage extends ConsumerWidget {
|
|||
onRefresh: () async {
|
||||
ref.invalidate(contributionProvider(accountSequence));
|
||||
ref.invalidate(contributionStatsProvider);
|
||||
ref.invalidate(marketOverviewProvider);
|
||||
ref.invalidate(sharePoolBalanceProvider);
|
||||
},
|
||||
child: hasError && contribution == null
|
||||
? Center(
|
||||
|
|
@ -78,7 +76,7 @@ class ContributionPage extends ConsumerWidget {
|
|||
sliver: SliverList(
|
||||
delegate: SliverChildListDelegate([
|
||||
// 总贡献值卡片
|
||||
_buildTotalContributionCard(ref, contribution, isLoading, market, isMarketLoading),
|
||||
_buildTotalContributionCard(ref, contribution, isLoading, sharePoolBalance, isSharePoolLoading),
|
||||
const SizedBox(height: 16),
|
||||
// 三栏统计
|
||||
_buildThreeColumnStats(ref, contribution, isLoading),
|
||||
|
|
@ -167,8 +165,8 @@ class ContributionPage extends ConsumerWidget {
|
|||
WidgetRef ref,
|
||||
Contribution? contribution,
|
||||
bool isLoading,
|
||||
MarketOverview? market,
|
||||
bool isMarketLoading,
|
||||
SharePoolBalance? sharePoolBalance,
|
||||
bool isSharePoolLoading,
|
||||
) {
|
||||
final total = contribution?.totalContribution ?? '0';
|
||||
final hideAmounts = ref.watch(hideAmountsProvider);
|
||||
|
|
@ -220,13 +218,13 @@ class ContributionPage extends ConsumerWidget {
|
|||
'积分股池实时余量: ',
|
||||
style: TextStyle(fontSize: 12, color: _grayText.withOpacity(0.9)),
|
||||
),
|
||||
isMarketLoading
|
||||
isSharePoolLoading
|
||||
? const ShimmerText(
|
||||
placeholder: '----',
|
||||
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: _orange),
|
||||
)
|
||||
: Text(
|
||||
hideAmounts ? '******' : formatAmount(market?.greenPoints ?? '0'),
|
||||
hideAmounts ? '******' : formatAmount(sharePoolBalance?.total ?? '0'),
|
||||
style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: _orange),
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import '../../domain/entities/contribution_stats.dart';
|
|||
import '../../domain/usecases/contribution/get_user_contribution.dart';
|
||||
import '../../domain/repositories/contribution_repository.dart';
|
||||
import '../../core/di/injection.dart';
|
||||
import '../../core/network/api_client.dart';
|
||||
import '../../core/network/api_endpoints.dart';
|
||||
|
||||
final getUserContributionUseCaseProvider = Provider<GetUserContribution>((ref) {
|
||||
return getIt<GetUserContribution>();
|
||||
|
|
@ -176,3 +178,38 @@ final estimatedEarningsProvider = Provider.family<EstimatedEarnings, String>((re
|
|||
|
||||
/// 控制是否隐藏金额显示的状态
|
||||
final hideAmountsProvider = StateProvider<bool>((ref) => false);
|
||||
|
||||
/// 积分股池余量数据类
|
||||
class SharePoolBalance {
|
||||
final String poolA;
|
||||
final String poolB;
|
||||
final String total;
|
||||
|
||||
const SharePoolBalance({
|
||||
required this.poolA,
|
||||
required this.poolB,
|
||||
required this.total,
|
||||
});
|
||||
|
||||
factory SharePoolBalance.fromJson(Map<String, dynamic> json) {
|
||||
return SharePoolBalance(
|
||||
poolA: json['poolA'] ?? '0',
|
||||
poolB: json['poolB'] ?? '0',
|
||||
total: json['total'] ?? '0',
|
||||
);
|
||||
}
|
||||
|
||||
static const zero = SharePoolBalance(poolA: '0', poolB: '0', total: '0');
|
||||
}
|
||||
|
||||
/// 积分股池总余量 Provider
|
||||
final sharePoolBalanceProvider = FutureProvider<SharePoolBalance>((ref) async {
|
||||
final client = getIt<ApiClient>();
|
||||
|
||||
try {
|
||||
final response = await client.get(ApiEndpoints.sharePoolBalance);
|
||||
return SharePoolBalance.fromJson(response.data as Map<String, dynamic>);
|
||||
} catch (e) {
|
||||
return SharePoolBalance.zero;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue