Skip to content

Commit

Permalink
fix(AccountsNotifier): 🐛 Remove Accounts illegal modifications
Browse files Browse the repository at this point in the history
Account & AccountsNotifierState are now immutable. This prevent modifying the objects without the Notifier to know.
  • Loading branch information
Chralu committed Jan 14, 2025
1 parent d37c6a4 commit 96c093b
Show file tree
Hide file tree
Showing 18 changed files with 898 additions and 316 deletions.
256 changes: 129 additions & 127 deletions lib/application/account/account_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,129 +115,131 @@ class AccountNotifier extends _$AccountNotifier {
}

Future<void> updateBalance() async {
final account = await future;
if (account == null) return;

var totalUSD = 0.0;
await _update((account) async {
var totalUSD = 0.0;

final balanceGetResponseMap = await ref
.read(appServiceProvider)
.getBalanceGetResponse([account.genesisAddress]);
final balanceGetResponseMap = await ref
.read(appServiceProvider)
.getBalanceGetResponse([account.genesisAddress]);

if (balanceGetResponseMap[account.genesisAddress] == null) {
return;
}
if (balanceGetResponseMap[account.genesisAddress] == null) {
return account;
}

final ucidsTokens = await ref.read(
aedappfm.UcidsTokensProviders.ucidsTokens(
environment: ref.read(environmentProvider),
).future,
);
final ucidsTokens = await ref.read(
aedappfm.UcidsTokensProviders.ucidsTokens(
environment: ref.read(environmentProvider),
).future,
);

final cryptoPrice = ref.read(aedappfm.CoinPriceProviders.coinPrices);
final cryptoPrice = ref.read(aedappfm.CoinPriceProviders.coinPrices);

final balanceGetResponse = balanceGetResponseMap[account.genesisAddress]!;
final ucoAmount = fromBigInt(balanceGetResponse.uco).toDouble();
final accountBalance = AccountBalance(
nativeTokenName: AccountBalance.cryptoCurrencyLabel,
nativeTokenValue: ucoAmount,
);
final balanceGetResponse = balanceGetResponseMap[account.genesisAddress]!;
final ucoAmount = fromBigInt(balanceGetResponse.uco).toDouble();
final accountBalance = AccountBalance(
nativeTokenName: AccountBalance.cryptoCurrencyLabel,
nativeTokenValue: ucoAmount,
);

if (balanceGetResponse.uco > 0) {
accountBalance.tokensFungiblesNb++;
if (balanceGetResponse.uco > 0) {
accountBalance.tokensFungiblesNb++;

final archethicOracleUCO = await ref.read(
aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.future,
);
totalUSD = (Decimal.parse(totalUSD.toString()) +
Decimal.parse(ucoAmount.toString()) *
Decimal.parse(archethicOracleUCO.usd.toString()))
.toDouble();
}
final archethicOracleUCO = await ref.read(
aedappfm.ArchethicOracleUCOProviders.archethicOracleUCO.future,
);
totalUSD = (Decimal.parse(totalUSD.toString()) +
Decimal.parse(ucoAmount.toString()) *
Decimal.parse(archethicOracleUCO.usd.toString()))
.toDouble();
}

for (final token in balanceGetResponse.token) {
if (token.tokenId != null) {
if (token.tokenId == 0) {
accountBalance.tokensFungiblesNb++;

final ucidsToken = ucidsTokens[token.address];
if (ucidsToken != null && ucidsToken != 0) {
final amountTokenUSD =
(Decimal.parse(fromBigInt(token.amount).toString()) *
Decimal.parse(
aedappfm.CoinPriceRepositoryImpl()
.getPriceFromUcid(ucidsToken, cryptoPrice)
.toString(),
))
.toDouble();
totalUSD = totalUSD + amountTokenUSD;
for (final token in balanceGetResponse.token) {
if (token.tokenId != null) {
if (token.tokenId == 0) {
accountBalance.tokensFungiblesNb++;

final ucidsToken = ucidsTokens[token.address];
if (ucidsToken != null && ucidsToken != 0) {
final amountTokenUSD =
(Decimal.parse(fromBigInt(token.amount).toString()) *
Decimal.parse(
aedappfm.CoinPriceRepositoryImpl()
.getPriceFromUcid(ucidsToken, cryptoPrice)
.toString(),
))
.toDouble();
totalUSD = totalUSD + amountTokenUSD;
}
} else {
accountBalance.nftNb++;
}
} else {
accountBalance.nftNb++;
}
}
}
accountBalance.totalUSD = totalUSD;
accountBalance.totalUSD = totalUSD;

account.balance = accountBalance;
await updateAccount();
return account.copyWith(balance: accountBalance);
});
}

Future<void> updateFungiblesTokens() async {
final account = await future;
if (account == null) {
return;
}
final appService = ref.read(appServiceProvider);
final poolsListRaw = await ref.read(DexPoolProviders.getPoolListRaw.future);

account.accountTokens = await appService.getFungiblesTokensList(
account.genesisAddress,
poolsListRaw,
);
await updateAccount();
await _update((account) async {
final appService = ref.read(appServiceProvider);
final poolsListRaw =
await ref.read(DexPoolProviders.getPoolListRaw.future);

return account.copyWith(
accountTokens: await appService.getFungiblesTokensList(
account.genesisAddress,
poolsListRaw,
),
);
});
}

Future<void> updateRecentTransactions() async {
final account = await future;
if (account == null) {
return;
}
final session = ref.read(sessionNotifierProvider).loggedIn!;
final appService = ref.read(appServiceProvider);

account
..recentTransactions = await appService.getAccountRecentTransactions(
account.genesisAddress,
account.name,
session.wallet.keychainSecuredInfos,
account.recentTransactions ?? [],
)
..lastLoadingTransactionInputs = DateTime.now().millisecondsSinceEpoch ~/
Duration.millisecondsPerSecond;
await updateAccount();
await _update((account) async {
final session = ref.read(sessionNotifierProvider).loggedIn!;
final appService = ref.read(appServiceProvider);

return account.copyWith(
recentTransactions: await appService.getAccountRecentTransactions(
account.genesisAddress,
account.name,
session.wallet.keychainSecuredInfos,
account.recentTransactions ?? [],
),
lastLoadingTransactionInputs: DateTime.now().millisecondsSinceEpoch ~/
Duration.millisecondsPerSecond,
);
});
}

Future<void> addCustomTokenAddress(String tokenAddress) async {
final account = await future;
if (account == null) {
return;
}

if (Address(address: tokenAddress).isValid() == false) return;
(account.customTokenAddressList ??= []).add(tokenAddress.toUpperCase());
await updateAccount();
await _update((account) async {
return account.copyWith(
customTokenAddressList: [
...account.customTokenAddressList ?? [],
tokenAddress.toUpperCase(),
],
);
});
}

Future<void> removeCustomTokenAddress(String tokenAddress) async {
final account = await future;
if (account == null) {
return;
}

if (Address(address: tokenAddress).isValid() == false) return;
(account.customTokenAddressList ??= []).remove(tokenAddress.toUpperCase());
await updateAccount();
await _update((account) async {
final customTokenAddressList = account.customTokenAddressList;
if (customTokenAddressList == null) return account;

return account.copyWith(
customTokenAddressList: customTokenAddressList
.where(
(element) => element != tokenAddress.toUpperCase(),
)
.toList(),
);
});
}

Future<bool> checkCustomTokenAddress(String tokenAddress) async {
Expand All @@ -252,42 +254,42 @@ class AccountNotifier extends _$AccountNotifier {
}

Future<void> updateNFT() async {
final account = await future;
if (account == null) {
return;
}
final session = ref.read(sessionNotifierProvider).loggedIn!;
final tokenInformation = await ref.read(
NFTProviders.getNFTList(
account.genesisAddress,
account.name,
session.wallet.keychainSecuredInfos,
).future,
);

account
..accountNFT = tokenInformation.$1
..accountNFTCollections = tokenInformation.$2;
await _update(
(account) async {
final session = ref.read(sessionNotifierProvider).loggedIn!;
final tokenInformation = await ref.read(
NFTProviders.getNFTList(
account.genesisAddress,
account.name,
session.wallet.keychainSecuredInfos,
).future,
);

await updateAccount();
return account.copyWith(
accountNFT: tokenInformation.$1,
accountNFTCollections: tokenInformation.$2,
);
},
);
}

Future<void> clearRecentTransactionsFromCache() async {
final account = await future;
if (account == null) {
return;
}

account.recentTransactions = [];
await updateAccount();
await _update(
(account) => account.copyWith(recentTransactions: []),
);
}

Future<void> updateAccount() async {
final account = await future;
if (account == null) {
return;
}
Future<void> _update(
FutureOr<Account> Function(Account) doUpdate,
) async {
await update(
(account) async {
if (account == null) return null;

await AccountHiveDatasource.instance().updateAccount(account);
final newState = await doUpdate(account);
await AccountHiveDatasource.instance().updateAccount(newState);
return newState;
},
);
}
}
2 changes: 1 addition & 1 deletion lib/application/account/account_notifier.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 7 additions & 6 deletions lib/application/account/accounts_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'dart:async';

import 'package:aewallet/application/account/account_notifier.dart';
import 'package:aewallet/application/session/session.dart';
import 'package:aewallet/infrastructure/datasources/account.hive.dart';
import 'package:aewallet/infrastructure/repositories/local_account.dart';
import 'package:aewallet/model/data/account.dart';
import 'package:aewallet/util/account_formatters.dart';
Expand All @@ -16,7 +15,7 @@ part 'accounts_notifier.g.dart';
@riverpod
class AccountsNotifier extends _$AccountsNotifier {
@override
FutureOr<List<Account>> build() async {
FutureOr<Iterable<Account>> build() async {
final session = ref.watch(sessionNotifierProvider);
if (session.isLoggedOut) {
return [];
Expand Down Expand Up @@ -55,16 +54,18 @@ class AccountsNotifier extends _$AccountsNotifier {
return ref.read(accountNotifierProvider(accountName).notifier);
}

// TODO(Chralu): check if this works
Future<void> clearRecentTransactionsFromCache() async {
final accounts = await future;
for (final account in accounts) {
account.recentTransactions = [];
await AccountHiveDatasource.instance().updateAccount(account);
await ref
.read(accountNotifierProvider(account.name).notifier)
.clearRecentTransactionsFromCache();
}
}
}

extension AccountsExt on List<Account> {
extension AccountsExt on Iterable<Account> {
Account? get selectedAccount {
for (final account in this) {
if (account.selected == true) return account;
Expand All @@ -91,7 +92,7 @@ extension AccountsExt on List<Account> {
}
}

extension FutureAccountsExt on Future<List<Account>> {
extension FutureAccountsExt on Future<Iterable<Account>> {
Future<Account?> get selectedAccount async {
return (await this).selectedAccount;
}
Expand Down
8 changes: 4 additions & 4 deletions lib/application/account/accounts_notifier.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 96c093b

Please sign in to comment.