Skip to content

Commit

Permalink
feat: Ton hamster (#778)
Browse files Browse the repository at this point in the history
* Auto enable ton and hamster

* Update default assets one second delay

* Cache by account address

* remove dependency_overrides flutter_rust_bridge
  • Loading branch information
knightsforce authored Feb 11, 2025
1 parent 0550c23 commit ceefbd7
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 24 deletions.
10 changes: 10 additions & 0 deletions assets/configs/connections.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@
"networkName": "TON",
"networkType": "ton",
"networkGroup": "ton",
"defaultActiveAssets": [
{
"address": "0:09f2e59dec406ab26a5259a45d7ff23ef11f3e5c7c21de0b0d2a1cbe52b76b3d"
}
],
"icons": {
"nativeToken": "https://raw.githubusercontent.com/broxus/sparx-networks/master/icons/ton/native_token.svg",
"network": "https://raw.githubusercontent.com/broxus/sparx-networks/master/icons/ton/network.svg",
Expand Down Expand Up @@ -167,6 +172,11 @@
"networkName": "Hamster Network",
"networkType": "tycho",
"networkGroup": "hmstr_mainnet",
"defaultActiveAssets": [
{
"address": "0:fddc005ddffcc9c5cc8e2d684c1338d3fa5548426602b04b2cfd2a1a3504be80"
}
],
"icons": {
"nativeToken": "https://raw.githubusercontent.com/broxus/sparx-networks/master/icons/hamster/native_token.svg",
"network": "https://raw.githubusercontent.com/broxus/sparx-networks/master/icons/hamster/network.svg",
Expand Down
102 changes: 100 additions & 2 deletions lib/app/service/assets_service.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'dart:async';
import 'dart:convert';

import 'package:app/app/service/connection/connection_factory.dart';
import 'package:app/app/service/presets_connection/presets_connection_service.dart';
import 'package:app/app/service/service.dart';
import 'package:app/data/models/models.dart';
import 'package:app/http/repository/ton_repository.dart';
Expand All @@ -17,6 +19,9 @@ import 'package:rxdart/rxdart.dart';
class AssetsService {
AssetsService(
this.nekotonRepository,
this.connectionsStorageService,
this.currentAccountsService,
this.presetsConnectionService,
this.httpService,
this.storage,
this.connectionFactory,
Expand All @@ -26,16 +31,26 @@ class AssetsService {
static final _logger = Logger('AssetsService');

final NekotonRepository nekotonRepository;
final ConnectionsStorageService connectionsStorageService;
final CurrentAccountsService currentAccountsService;
final PresetsConnectionService presetsConnectionService;
final HttpService httpService;
final GeneralStorageService storage;
final ConnectionFactory connectionFactory;
final TonRepository tonRepository;

StreamSubscription<TransportStrategy>? _currentTransportSubscription;
StreamSubscription<KeyAccount?>? _accountsSubscription;
StreamSubscription<String>? _connectionsSubscription;
StreamSubscription<void>? _combineSubscription;

/// Start listening for transport changes and update contracts from manifest
void init() {
nekotonRepository.currentTransportStream.listen(_updateSystemContracts);
_currentTransportSubscription =
nekotonRepository.currentTransportStream.listen(_updateSystemContracts);

nekotonRepository.currentTransportStream.flatMap((transport) {
_combineSubscription =
nekotonRepository.currentTransportStream.flatMap((transport) {
return Rx.combineLatest2<List<TokenContractAsset>,
List<TokenContractAsset>, void>(
storage.systemTokenContractAssetsStream(transport.transport.group),
Expand All @@ -45,6 +60,24 @@ class AssetsService {
// listen needs to enable stream api
// ignore: no-empty-block
}).listen((_) {});

_connectionsSubscription =
connectionsStorageService.currentConnectionIdStream.listen(
(_) => updateDefaultAssets(),
);

_accountsSubscription =
currentAccountsService.currentActiveAccountStream.listen(
(_) => updateDefaultAssets(),
);
}

@disposeMethod
void dispose() {
_currentTransportSubscription?.cancel();
_accountsSubscription?.cancel();
_connectionsSubscription?.cancel();
_combineSubscription?.cancel();
}

/// Get list of contracts (custom and system) that is available for current
Expand Down Expand Up @@ -247,6 +280,17 @@ class AssetsService {
}
}

Future<void> updateDefaultActiveAssets(
String accountAddress,
List<String> address,
) async {
return storage.updateDefaultActiveAssets(accountAddress, address);
}

List<String> getDefaultActiveAssets(String accountAddress) {
return storage.getDefaultActiveAssets(accountAddress);
}

/// Try getting contract of existed token contract from storage.
/// This can be helpful when you know, that token exists, but you do not have
/// direct access to TokenWallet.
Expand All @@ -268,6 +312,60 @@ class AssetsService {
nekotonRepository.currentTransport.transport.group,
);

Future<void> updateDefaultAssets() async {
await Future.delayed(const Duration(seconds: 1), () async {
final presetsDefaultAssets =
presetsConnectionService.getDefaultActiveAsset(
connectionsStorageService.currentConnection.group,
);

if (presetsDefaultAssets.isEmpty) {
return;
}

final accountAddress =
currentAccountsService.currentActiveAccount?.address;

if (accountAddress == null) {
return;
}

final cachedAccount = nekotonRepository.seedList.findAccountByAddress(
accountAddress,
);

if (cachedAccount == null) {
return;
}

final cachedDefaultAssets =
getDefaultActiveAssets(accountAddress.address);

final result = <Address>[];
final skipped = <String>[];

for (final preset in presetsDefaultAssets) {
if (cachedDefaultAssets.contains(preset.address.address)) {
continue;
}
result.add(preset.address);
skipped.add(preset.address.address);
}

if (result.isNotEmpty) {
await cachedAccount.addTokenWallets(result);
}
if (skipped.isNotEmpty) {
unawaited(
updateDefaultActiveAssets(
accountAddress.address,
skipped,
),
);
}
});
}

/// Load manifest specified for transport and update system contracts that
/// user can add to list of its contracts.
Future<void> _updateSystemContracts(TransportStrategy transport) async {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:app/app/service/connection/data/account_explorer/account_explorer_link_type.dart';
import 'package:app/app/service/connection/data/default_active_asset.dart';
import 'package:app/app/service/connection/data/transaction_explorer/transaction_explorer_link_type.dart';
import 'package:app/app/service/connection/data/transport_icons.dart';
import 'package:app/app/service/connection/data/transport_manifest_option/transport_manifest_option.dart';
Expand Down Expand Up @@ -27,7 +28,8 @@ class ConnectionTransportData {
this.stakeInformation,
this.tokenApiBaseUrl,
this.currencyApiBaseUrl,
});
List<DefaultActiveAsset>? defaultActiveAssets,
}) : defaultActiveAssets = defaultActiveAssets ?? [];

factory ConnectionTransportData.custom({
required String networkType,
Expand Down Expand Up @@ -75,6 +77,7 @@ class ConnectionTransportData {
transactionExplorerLinkType: TransactionExplorerLinkType.transactions,
);

final List<DefaultActiveAsset> defaultActiveAssets;
final TransportIcons icons;
final List<WalletType> availableWalletTypes;
final WalletDefaultAccountNames walletDefaultAccountNames;
Expand Down
9 changes: 9 additions & 0 deletions lib/app/service/connection/data/default_active_asset.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:nekoton_repository/nekoton_repository.dart';

class DefaultActiveAsset {
DefaultActiveAsset({
required this.address,
});

final Address address;
}
19 changes: 19 additions & 0 deletions lib/app/service/connection/mapping/transports_mapper.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:app/app/service/connection/data/account_explorer/account_explorer_link_type.dart';
import 'package:app/app/service/connection/data/connection_transport/connection_transport_data.dart';
import 'package:app/app/service/connection/data/default_active_asset.dart';
import 'package:app/app/service/connection/data/transaction_explorer/transaction_explorer_link_type.dart';
import 'package:app/app/service/connection/data/transport_icons.dart';
import 'package:app/app/service/connection/data/transport_manifest_option/transport_manifest_option.dart';
Expand All @@ -17,6 +18,9 @@ Map<NetworkGroup, ConnectionTransportData>? mapToTransports(

for (final transport in list) {
result[transport['networkGroup'] as String] = ConnectionTransportData(
defaultActiveAssets: _mapToDefaultActiveAssets(
transport['defaultActiveAssets'],
),
icons: _mapToTransportIcons(
transport['icons'] as Map<String, dynamic>,
),
Expand Down Expand Up @@ -187,3 +191,18 @@ WalletDefaultAccountNames _mapRoWalletDefaultAccountNames(
walletV5R1: json['walletV5R1'] as String,
);
}

List<DefaultActiveAsset> _mapToDefaultActiveAssets(dynamic json) {
try {
final list = castJsonList<Map<String, dynamic>>(json);

return [
for (final item in list)
DefaultActiveAsset(
address: Address(address: item['address'] as String),
),
];
} catch (_) {
return [];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:async';
import 'package:app/app/service/connection/data/connection_data/connection_data.dart';
import 'package:app/app/service/connection/data/connection_network/connection_network.dart';
import 'package:app/app/service/connection/data/connection_transport/connection_transport_data.dart';
import 'package:app/app/service/connection/data/default_active_asset.dart';
import 'package:app/app/service/connection/data/transport_icons.dart';
import 'package:app/app/service/connection/default_network.dart';
import 'package:app/app/service/connection/group.dart';
Expand Down Expand Up @@ -59,6 +60,10 @@ class PresetsConnectionService {
return transports[networkGroup]?.icons ?? TransportIcons();
}

List<DefaultActiveAsset> getDefaultActiveAsset(NetworkGroup group) {
return transports[group]?.defaultActiveAssets ?? [];
}

Future<void> fetchConnectionsList() async {
_presetsConnectionsSubj.add(await _configHelper.connections);
}
Expand Down
31 changes: 31 additions & 0 deletions lib/app/service/storage_service/general_storage_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ const _currentAddress = 'current_address';
const _currentKey = 'current_public_key';

const _customContractAssetsKey = 'custom_contract_assets_key';
const _defaultActiveAssetsStorageKey = 'default_active_assets_storage_key';
const _lastSelectedSeedsKey = 'last_selected_seeds_key';
const _migrationKey = 'migration_key';
const _preferencesKey = 'preferences_key';
const _systemContractAssetsKey = 'system_contract_assets_key';
const _wasStEverOpenedKey = 'was_stever_opened_key';
const _alreadyAutoEnabledDefaultActiveAssets =
'already_auto_enabled_default_active_assets';

/// This is a wrapper-class above [GetStorage] that provides methods
/// to interact with general information that is not related to some specified
Expand All @@ -35,23 +38,27 @@ class GeneralStorageService extends AbstractStorageService {
@Named(currenciesContainer) this._currenciesStorage,
@Named(systemContractAssetsContainer) this._systemContractAssetsStorage,
@Named(customContractAssetsContainer) this._customContractAssetsStorage,
@Named(defaultActiveAssetsStorage) this._defaultActiveAssetsStorage,
);

static const prefContainer = _preferencesKey;
static const currenciesContainer = _currenciesKey;
static const systemContractAssetsContainer = _systemContractAssetsKey;
static const customContractAssetsContainer = _customContractAssetsKey;
static const defaultActiveAssetsStorage = _defaultActiveAssetsStorageKey;
static const containers = [
prefContainer,
currenciesContainer,
systemContractAssetsContainer,
customContractAssetsContainer,
defaultActiveAssetsStorage,
];

final GetStorage _prefStorage;
final GetStorage _currenciesStorage;
final GetStorage _systemContractAssetsStorage;
final GetStorage _customContractAssetsStorage;
final GetStorage _defaultActiveAssetsStorage;

/// Subject of public keys names
final _currentKeySubject = BehaviorSubject<PublicKey?>();
Expand Down Expand Up @@ -402,6 +409,30 @@ class GeneralStorageService extends AbstractStorageService {
}
}

void updateDefaultActiveAssets(
String accountAddress,
List<String> addresses,
) {
_defaultActiveAssetsStorage.write(
'$_alreadyAutoEnabledDefaultActiveAssets-$accountAddress',
getDefaultActiveAssets(accountAddress)
..addAll(addresses)
..toSet()
..toList(),
);
}

List<String> getDefaultActiveAssets(String accountAddress) {
return _defaultActiveAssetsStorage
.read<List<dynamic>?>(
'$_alreadyAutoEnabledDefaultActiveAssets-$accountAddress',
)
?.cast<String>()
.toSet()
.toList() ??
[];
}

Future<void> _initAppDirectories() async {
final directory = await getApplicationDocumentsDirectory();
_applicationDocumentsDirectory = directory.path;
Expand Down
Loading

0 comments on commit ceefbd7

Please sign in to comment.