Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: balances module #1476

Merged
merged 4 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../../../ui/theme.dart';
import '../../../ui/value_stream_builder.dart';
import '../../activities/services/tx_updater.dart';
import '../../activities/widgets/recent_activity.dart';
import '../../conversion_rates/services/watch_cash_fiat_balance.dart';
import '../../conversion_rates/services/token_fiat_balance_service.dart';
import '../../investments/services/watch_investments.dart';
import '../../tokens/token.dart';
import '../widgets/home_add_cash.dart';
Expand All @@ -33,8 +33,12 @@ class MainScreen extends StatelessWidget {
@override
Widget build(BuildContext context) => CpTheme.dark(
child: ValueStreamBuilder<bool>(
create: () =>
sl<WatchUserCashBalance>().call().map((it) => it.isZero),
create: () => (
sl<TokenFiatBalanceService>()
.watchMainBalance()
.map((it) => it.isZero),
true,
),
builder: (context, isZeroAmount) => isZeroAmount
? const HomeAddCashContent()
: _MainContent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import 'package:flutter/material.dart';
import '../../../di.dart';
import '../../../l10n/device_locale.dart';
import '../../../ui/value_stream_builder.dart';
import '../../conversion_rates/services/watch_cash_fiat_balance.dart';
import '../../conversion_rates/services/token_fiat_balance_service.dart';
import '../../conversion_rates/widgets/extensions.dart';
import '../../currency/models/amount.dart';
import '../../currency/models/currency.dart';
import '../../tokens/token.dart';
import '../../tokens/widgets/token_icon.dart';

Expand All @@ -15,7 +16,10 @@ class BalanceAmount extends StatelessWidget {

@override
Widget build(BuildContext context) => ValueStreamBuilder<Amount>(
create: () => sl<WatchUserCashBalance>().call(),
create: () => (
sl<TokenFiatBalanceService>().watchMainBalance(),
Amount.zero(currency: Currency.usd),
),
builder: (context, amount) {
final formattedAmount = amount.format(
DeviceLocale.localeOf(context),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import '../../../ui/button.dart';
import '../../../ui/colors.dart';
import '../../../ui/info_icon.dart';
import '../../../ui/value_stream_builder.dart';
import '../../conversion_rates/services/watch_cash_fiat_balance.dart';
import '../../conversion_rates/services/token_fiat_balance_service.dart';
import '../../ramp/widgets/ramp_buttons.dart';
import 'balance_amount.dart';

Expand Down Expand Up @@ -68,8 +68,12 @@ class _Buttons extends StatelessWidget {
),
),
child: ValueStreamBuilder<bool>(
create: () =>
sl<WatchUserCashBalance>().call().map((it) => it.isZero),
create: () => (
sl<TokenFiatBalanceService>()
.watchMainBalance()
.map((it) => it.isZero),
true,
),
builder: (context, isZeroAmount) => Padding(
padding: const EdgeInsets.only(
left: 18,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import '../../../ui/colors.dart';
import '../../../ui/home_tile.dart';
import '../../../ui/theme.dart';
import '../../../ui/value_stream_builder.dart';
import '../../balances/data/token_balance_repository.dart';
import '../../conversion_rates/services/watch_token_fiat_balance.dart';
import '../../conversion_rates/services/watch_token_total_balance.dart';
import '../../balances/data/repository.dart';
import '../../conversion_rates/services/token_fiat_balance_service.dart';
import '../../conversion_rates/widgets/extensions.dart';
import '../../currency/models/amount.dart';
import '../../currency/models/currency.dart';
Expand Down Expand Up @@ -78,7 +77,7 @@ class PortfolioTile extends StatelessWidget {
const SizedBox(width: 8),
ValueStreamBuilder<Amount>(
create: () => (
sl<WatchTotalTokenFiatBalance>().call(),
sl<TokenFiatBalanceService>().watchTotal(),
Amount.zero(currency: Currency.usd),
),
builder: (context, balance) => Flexible(
Expand Down Expand Up @@ -142,7 +141,7 @@ class _TokenItem extends StatelessWidget {

@override
Widget build(BuildContext context) => ValueStreamBuilder<Amount?>(
create: () => (sl<WatchTokenFiatBalance>().call(amount.token), null),
create: () => (sl<TokenFiatBalanceService>().watch(amount.token), null),
builder: (context, fiatAmount) {
String fiatAmountText;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import '../../../gen/assets.gen.dart';
import '../../../l10n/l10n.dart';
import '../../../ui/snackbar.dart';
import '../../../utils/processing_state.dart';
import '../../balances/data/token_balance_repository.dart';
import '../../balances/data/repository.dart';
import '../../balances/services/balances_bloc.dart';
import '../../balances/widgets/context_ext.dart';
import '../../conversion_rates/data/repository.dart';
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@ class TokenBalancesRepository {
final MyDatabase _db;
final TokenList _tokens;

Future<CryptoAmount> read(Token token) async {
final query = _db.tokenBalanceRows.select()
..where((tbl) => tbl.token.equals(token.address));

final row = await query.getSingleOrNull();

return row == null
? CryptoAmount(value: 0, cryptoCurrency: CryptoCurrency(token: token))
: CryptoAmount(
value: row.amount,
cryptoCurrency: CryptoCurrency(token: token),
);
}

Future<ISet<Token>> readUserTokens() {
final query = _db.tokenBalanceRows.select()
..where((tbl) => tbl.amount.isBiggerThanValue(0));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:async';

import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:collection/collection.dart';
import 'package:dfunc/dfunc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
Expand All @@ -17,8 +18,7 @@ import '../../currency/models/amount.dart';
import '../../currency/models/currency.dart';
import '../../tokens/token.dart';
import '../../tokens/token_list.dart';
import '../data/cash_balance_repository.dart';
import '../data/token_balance_repository.dart';
import '../data/repository.dart';

part 'balances_bloc.freezed.dart';

Expand All @@ -30,7 +30,6 @@ class BalancesBloc extends Bloc<BalancesEvent, BalancesState>
with DisposableBloc {
BalancesBloc(
this._solanaClient,
this._usdcRepository,
this._tokens,
this._tokensRepository,
this._analyticsManager,
Expand All @@ -40,7 +39,6 @@ class BalancesBloc extends Bloc<BalancesEvent, BalancesState>

final SolanaClient _solanaClient;
final TokenList _tokens;
final CashBalanceRepository _usdcRepository;
final TokenBalancesRepository _tokensRepository;
final AnalyticsManager _analyticsManager;

Expand All @@ -51,20 +49,7 @@ class BalancesBloc extends Bloc<BalancesEvent, BalancesState>
try {
emit(const ProcessingState.processing());

final usdcBalance = await _solanaClient.getUsdcBalance(event.address);

if (isClosed) return;

emit(const ProcessingState.none());

if (usdcBalance != null) {
_usdcRepository.save(usdcBalance);
_analyticsManager.setUsdcBalance(usdcBalance.decimal);
}

final balances = <Token, CryptoAmount>{};

balances[Token.sol] = await _solanaClient.getSolBalance(event.address);
final sol = await _solanaClient.getSolBalance(event.address);

final allAccounts = await _solanaClient.getSplAccounts(event.address);
final mainAccounts = await Future.wait<_MainTokenAccount?>(
Expand Down Expand Up @@ -94,7 +79,20 @@ class BalancesBloc extends Bloc<BalancesEvent, BalancesState>
cryptoCurrency: CryptoCurrency(token: a.token),
),
);
await _tokensRepository.save(tokenBalances);

final usdcBalance = tokenBalances.firstWhereOrNull(
(balance) => balance.cryptoCurrency.token == Token.usdc,
);

if (isClosed) return;

emit(const ProcessingState.none());

if (usdcBalance != null) {
_analyticsManager.setUsdcBalance(usdcBalance.decimal);
}

await _tokensRepository.save([...tokenBalances, sol]);
} on Exception catch (exception) {
_logger.severe('Failed to fetch balances', exception);

Expand Down Expand Up @@ -144,29 +142,6 @@ sealed class BalancesEvent with _$BalancesEvent {
}

extension on SolanaClient {
Future<CryptoAmount?> getUsdcBalance(String address) async {
try {
final usdcTokenAccount = await findAssociatedTokenAddress(
owner: Ed25519HDPublicKey.fromBase58(address),
mint: Ed25519HDPublicKey.fromBase58(Token.usdc.address),
);

final balance = await rpcClient
.getTokenAccountBalance(
usdcTokenAccount.toBase58(),
commitment: Commitment.confirmed,
)
.value;

return CryptoAmount(
value: int.parse(balance.amount),
cryptoCurrency: Currency.usdc,
);
} on Exception {
return null;
}
}

Future<CryptoAmount> getSolBalance(String address) async {
final lamports = await rpcClient
.getBalance(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import 'package:collection/collection.dart';
import 'package:injectable/injectable.dart';
import 'package:rxdart/rxdart.dart';

import '../../balances/data/token_balance_repository.dart';
import '../../balances/data/repository.dart';
import '../../currency/models/amount.dart';
import '../../currency/models/currency.dart';
import '../../tokens/token.dart';
import '../data/repository.dart';

@injectable
class WatchTokenFiatBalance {
const WatchTokenFiatBalance(
class TokenFiatBalanceService {
const TokenFiatBalanceService(
this._conversionRatesRepository,
this._balancesRepository,
);

final ConversionRatesRepository _conversionRatesRepository;
final TokenBalancesRepository _balancesRepository;

Stream<FiatAmount?> call(Token token) {
Stream<FiatAmount?> watch(Token token) {
const fiatCurrency = defaultFiatCurrency;
final conversionRate = _conversionRatesRepository.watchRate(
CryptoCurrency(token: token),
Expand All @@ -36,4 +37,21 @@ class WatchTokenFiatBalance {
},
).distinct();
}

Stream<FiatAmount> watchTotal() => _balancesRepository
.watchUserTokens(ignoreTokens: [Token.usdc])
.flatMap(
(tokens) => Rx.combineLatest(
tokens.map(watch),
(values) => values.whereNotNull().fold(
const FiatAmount(value: 0, fiatCurrency: defaultFiatCurrency),
(total, next) => (total + next) as FiatAmount,
),
),
)
.distinct();

Stream<FiatAmount> watchMainBalance() => watch(Token.usdc).map(
(it) => it ?? const FiatAmount(value: 0, fiatCurrency: Currency.usd),
);
}
Loading
Loading