mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-23 03:05:11 +00:00
receive screen + node screen working
This commit is contained in:
parent
2670eb2868
commit
9ebf74fa01
14 changed files with 227 additions and 199 deletions
|
@ -1,4 +1,2 @@
|
|||
-
|
||||
uri: rpc.nano.to
|
||||
-
|
||||
uri: eth.llamarpc.com
|
||||
uri: rpc.nano.to
|
|
@ -70,6 +70,8 @@ class Node extends HiveObject with Keyable {
|
|||
return Uri.http(uriRaw, '');
|
||||
case WalletType.ethereum:
|
||||
return Uri.https(uriRaw, '');
|
||||
case WalletType.nano:
|
||||
return Uri.https(uriRaw, '');
|
||||
default:
|
||||
throw Exception('Unexpected type ${type.toString()} for Node uri');
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ class NanoBalance extends Balance {
|
|||
// moneroParseAmount(amount: formattedCurrentBalance));
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => "error";
|
||||
String get formattedAvailableBalance => "0";
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance => "error";
|
||||
String get formattedAdditionalBalance => "0";
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ abstract class NanoWalletBase
|
|||
|
||||
late final String _privateKey;
|
||||
late final String _publicAddress;
|
||||
late final String _seed;
|
||||
late final String _seedKey;
|
||||
|
||||
List<int> _priorityFees;
|
||||
int? _gasPrice;
|
||||
|
@ -74,14 +74,14 @@ abstract class NanoWalletBase
|
|||
@observable
|
||||
late ObservableMap<CryptoCurrency, NanoBalance> balance;
|
||||
|
||||
|
||||
// initialize the different forms of private / public key we'll need:
|
||||
Future<void> init() async {
|
||||
final String type = (_derivationType == DerivationType.nano) ? "standard" : "hd";
|
||||
|
||||
_seed = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
|
||||
_privateKey = await NanoUtil.uniSeedToPrivate(_mnemonic, 0, type);
|
||||
_publicAddress = await NanoUtil.uniSeedToAddress(_mnemonic, 0, type);
|
||||
_seedKey = bip39.mnemonicToEntropy(_mnemonic).toUpperCase();
|
||||
_privateKey = await NanoUtil.uniSeedToPrivate(_seedKey, 0, type);
|
||||
_publicAddress = await NanoUtil.uniSeedToAddress(_seedKey, 0, type);
|
||||
this.walletInfo.address = _publicAddress;
|
||||
|
||||
await walletAddresses.init();
|
||||
// await transactionHistory.init();
|
||||
|
@ -166,8 +166,10 @@ abstract class NanoWalletBase
|
|||
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||
|
||||
String toJSON() => json.encode({
|
||||
'seedKey': _seedKey,
|
||||
'mnemonic': _mnemonic,
|
||||
// 'balance': balance[currency]!.toJSON(),
|
||||
'derivationType': _derivationType.toString()
|
||||
});
|
||||
|
||||
static Future<NanoWallet> open({
|
||||
|
@ -175,7 +177,26 @@ abstract class NanoWalletBase
|
|||
required String password,
|
||||
required WalletInfo walletInfo,
|
||||
}) async {
|
||||
throw UnimplementedError();
|
||||
// TODO: finish
|
||||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||
final jsonSource = await read(path: path, password: password);
|
||||
final data = json.decode(jsonSource) as Map;
|
||||
final mnemonic = data['mnemonic'] as String;
|
||||
final balance = /*NanoBalance.fromJSON(data['balance'] as String) ?? */
|
||||
NanoBalance(currentBalance: BigInt.zero, receivableBalance: BigInt.zero);
|
||||
|
||||
DerivationType derivationType = DerivationType.bip39;
|
||||
if (data['derivationType'] == "nano") {
|
||||
derivationType = DerivationType.nano;
|
||||
}
|
||||
|
||||
return NanoWallet(
|
||||
walletInfo: walletInfo,
|
||||
password: password,
|
||||
mnemonic: mnemonic,
|
||||
initialBalance: balance,
|
||||
derivationType: derivationType,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _updateBalance() async {
|
||||
|
|
|
@ -37,20 +37,13 @@ class NanoWalletLoadingException implements Exception {
|
|||
}
|
||||
|
||||
class NanoRestoreWalletFromKeysCredentials extends WalletCredentials {
|
||||
NanoRestoreWalletFromKeysCredentials(
|
||||
{required String name,
|
||||
required String password,
|
||||
required this.language,
|
||||
required this.address,
|
||||
required this.viewKey,
|
||||
required this.spendKey,
|
||||
int height = 0})
|
||||
: super(name: name, password: password, height: height);
|
||||
NanoRestoreWalletFromKeysCredentials({
|
||||
required String name,
|
||||
required String password,
|
||||
required this.seedKey,
|
||||
}) : super(name: name, password: password);
|
||||
|
||||
final String language;
|
||||
final String address;
|
||||
final String viewKey;
|
||||
final String spendKey;
|
||||
final String seedKey;
|
||||
}
|
||||
|
||||
class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
||||
|
@ -108,33 +101,36 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
// await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
|
||||
print("a");
|
||||
throw UnimplementedError();
|
||||
// try {
|
||||
// final path = await pathForWallet(name: credentials.name, type: getType());
|
||||
// await monero_wallet_manager.restoreFromKeys(
|
||||
// path: path,
|
||||
// password: credentials.password!,
|
||||
// language: credentials.language,
|
||||
// restoreHeight: credentials.height!,
|
||||
// address: credentials.address,
|
||||
// viewKey: credentials.viewKey,
|
||||
// spendKey: credentials.spendKey);
|
||||
// final wallet = NanoWallet(walletInfo: credentials.walletInfo!);
|
||||
// await wallet.init();
|
||||
|
||||
// return wallet;
|
||||
// } catch (e) {
|
||||
// // TODO: Implement Exception for wallet list service.
|
||||
// print('NanoWalletsManager Error: $e');
|
||||
// rethrow;
|
||||
// }
|
||||
Future<DerivationType> compareDerivationMethods({String? mnemonic, String? seedKey}) async {
|
||||
// TODO:
|
||||
return DerivationType.nano;
|
||||
}
|
||||
|
||||
Future<DerivationType> compareDerivationMethods({String? mnemonic, String? seedKey}) async {
|
||||
return DerivationType.nano;
|
||||
@override
|
||||
Future<NanoWallet> restoreFromKeys(NanoRestoreWalletFromKeysCredentials credentials) async {
|
||||
throw UnimplementedError("restoreFromKeys");
|
||||
|
||||
DerivationType derivationType = DerivationType.bip39;
|
||||
|
||||
if (credentials.seedKey.length == 128) {
|
||||
derivationType = DerivationType.bip39;
|
||||
} else {
|
||||
// we don't know for sure, but probably the nano standard:
|
||||
derivationType = await compareDerivationMethods(seedKey: credentials.seedKey);
|
||||
}
|
||||
|
||||
String? mnemonic;
|
||||
|
||||
final wallet = await NanoWallet(
|
||||
password: credentials.password!,
|
||||
mnemonic: mnemonic ?? "", // we can't derive the mnemonic from the key in all cases
|
||||
walletInfo: credentials.walletInfo!,
|
||||
derivationType: derivationType,
|
||||
);
|
||||
|
||||
await wallet.init();
|
||||
await wallet.save();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -163,13 +159,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
|
|||
derivationType: derivationType,
|
||||
);
|
||||
|
||||
try {
|
||||
await wallet.init();
|
||||
} catch (e) {
|
||||
print("test");
|
||||
print(e);
|
||||
rethrow;
|
||||
}
|
||||
await wallet.init();
|
||||
await wallet.save();
|
||||
return wallet;
|
||||
}
|
||||
|
|
|
@ -44,37 +44,33 @@ Future defaultSettingsMigration(
|
|||
// check current nodes for nullability regardless of the version
|
||||
await checkCurrentNodes(nodes, sharedPreferences);
|
||||
|
||||
final isNewInstall = sharedPreferences
|
||||
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null;
|
||||
|
||||
await sharedPreferences.setBool(
|
||||
PreferencesKey.isNewInstall, isNewInstall);
|
||||
final isNewInstall =
|
||||
sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) == null;
|
||||
|
||||
await sharedPreferences.setBool(PreferencesKey.isNewInstall, isNewInstall);
|
||||
|
||||
final currentVersion = sharedPreferences
|
||||
.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ??
|
||||
0;
|
||||
|
||||
if (currentVersion >= version) {
|
||||
return;
|
||||
}
|
||||
|
||||
final migrationVersionsLength = version - currentVersion;
|
||||
final migrationVersions = List<int>.generate(
|
||||
migrationVersionsLength, (i) => currentVersion + (i + 1));
|
||||
final migrationVersions =
|
||||
List<int>.generate(migrationVersionsLength, (i) => currentVersion + (i + 1));
|
||||
|
||||
await Future.forEach(migrationVersions, (int version) async {
|
||||
try {
|
||||
switch (version) {
|
||||
case 1:
|
||||
await sharedPreferences.setString(
|
||||
PreferencesKey.currentFiatCurrencyKey,
|
||||
FiatCurrency.usd.toString());
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy,
|
||||
PreferencesKey.currentFiatCurrencyKey, FiatCurrency.usd.toString());
|
||||
await sharedPreferences.setInt(PreferencesKey.currentTransactionPriorityKeyLegacy,
|
||||
monero!.getDefaultTransactionPriority().raw);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey,
|
||||
BalanceDisplayMode.availableBalance.raw);
|
||||
PreferencesKey.currentBalanceDisplayModeKey, BalanceDisplayMode.availableBalance.raw);
|
||||
await sharedPreferences.setBool('save_recipient_address', true);
|
||||
await resetToDefault(nodes);
|
||||
await changeMoneroCurrentNodeToDefault(
|
||||
|
@ -83,14 +79,12 @@ Future defaultSettingsMigration(
|
|||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeLitecoinCurrentElectrumServerToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeHavenCurrentNodeToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeHavenCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
|
||||
break;
|
||||
case 2:
|
||||
await replaceNodesMigration(nodes: nodes);
|
||||
await replaceDefaultNode(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await replaceDefaultNode(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
|
||||
break;
|
||||
case 3:
|
||||
|
@ -140,8 +134,7 @@ Future defaultSettingsMigration(
|
|||
|
||||
case 16:
|
||||
await addHavenNodeList(nodes: nodes);
|
||||
await changeHavenCurrentNodeToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeHavenCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await checkCurrentNodes(nodes, sharedPreferences);
|
||||
break;
|
||||
|
||||
|
@ -164,6 +157,10 @@ Future defaultSettingsMigration(
|
|||
await changeEthereumCurrentNodeToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
break;
|
||||
case 22:
|
||||
await addNanoNodeList(nodes: nodes);
|
||||
await changeNanoCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -176,8 +173,7 @@ Future defaultSettingsMigration(
|
|||
}
|
||||
});
|
||||
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
}
|
||||
|
||||
Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPreferences) async {
|
||||
|
@ -187,8 +183,8 @@ Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPre
|
|||
final int? savedBitcoinPriority =
|
||||
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority);
|
||||
if (!bitcoin!.getTransactionPriorities().any((element) => element.raw == savedBitcoinPriority)) {
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.bitcoinTransactionPriority, bitcoin!.getMediumTransactionPriority().serialize());
|
||||
await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
bitcoin!.getMediumTransactionPriority().serialize());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,10 +201,9 @@ Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
|
|||
final replaceNodes = <String, Node>{
|
||||
'eu-node.cakewallet.io:18081':
|
||||
Node(uri: 'xmr-node-eu.cakewallet.com:18081', type: WalletType.monero),
|
||||
'node.cakewallet.io:18081': Node(
|
||||
uri: 'xmr-node-usa-east.cakewallet.com:18081', type: WalletType.monero),
|
||||
'node.xmr.ru:13666':
|
||||
Node(uri: 'node.monero.net:18081', type: WalletType.monero)
|
||||
'node.cakewallet.io:18081':
|
||||
Node(uri: 'xmr-node-usa-east.cakewallet.com:18081', type: WalletType.monero),
|
||||
'node.xmr.ru:13666': Node(uri: 'node.monero.net:18081', type: WalletType.monero)
|
||||
};
|
||||
|
||||
nodes.values.forEach((Node node) async {
|
||||
|
@ -224,8 +219,7 @@ Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
|
|||
}
|
||||
|
||||
Future<void> changeMoneroCurrentNodeToDefault(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final node = getMoneroDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int ?? 0; // 0 - England
|
||||
|
||||
|
@ -233,33 +227,30 @@ Future<void> changeMoneroCurrentNodeToDefault(
|
|||
}
|
||||
|
||||
Node? getBitcoinDefaultElectrumServer({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == cakeWalletBitcoinElectrumUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
|
||||
return nodes.values
|
||||
.firstWhereOrNull((Node node) => node.uriRaw == cakeWalletBitcoinElectrumUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
|
||||
}
|
||||
|
||||
Node? getLitecoinDefaultElectrumServer({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == cakeWalletLitecoinElectrumUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.litecoin);
|
||||
return nodes.values
|
||||
.firstWhereOrNull((Node node) => node.uriRaw == cakeWalletLitecoinElectrumUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.litecoin);
|
||||
}
|
||||
|
||||
Node? getHavenDefaultNode({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == havenDefaultNodeUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.haven);
|
||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == havenDefaultNodeUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.haven);
|
||||
}
|
||||
|
||||
Node? getEthereumDefaultNode({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == ethereumDefaultNodeUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
|
||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == ethereumDefaultNodeUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
|
||||
}
|
||||
|
||||
Node? getNanoDefaultNode({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull(
|
||||
(Node node) => node.uriRaw == nanoDefaultNodeUri)
|
||||
?? nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
|
||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == nanoDefaultNodeUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.ethereum);
|
||||
}
|
||||
|
||||
Node getMoneroDefaultNode({required Box<Node> nodes}) {
|
||||
|
@ -275,16 +266,14 @@ Node getMoneroDefaultNode({required Box<Node> nodes}) {
|
|||
}
|
||||
|
||||
try {
|
||||
return nodes.values
|
||||
.firstWhere((Node node) => node.uriRaw == nodeUri);
|
||||
} catch(_) {
|
||||
return nodes.values.firstWhere((Node node) => node.uriRaw == nodeUri);
|
||||
} catch (_) {
|
||||
return nodes.values.first;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changeBitcoinCurrentElectrumServerToDefault(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final server = getBitcoinDefaultElectrumServer(nodes: nodes);
|
||||
final serverId = server?.key as int ?? 0;
|
||||
|
||||
|
@ -292,8 +281,7 @@ Future<void> changeBitcoinCurrentElectrumServerToDefault(
|
|||
}
|
||||
|
||||
Future<void> changeLitecoinCurrentElectrumServerToDefault(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final server = getLitecoinDefaultElectrumServer(nodes: nodes);
|
||||
final serverId = server?.key as int ?? 0;
|
||||
|
||||
|
@ -301,8 +289,7 @@ Future<void> changeLitecoinCurrentElectrumServerToDefault(
|
|||
}
|
||||
|
||||
Future<void> changeHavenCurrentNodeToDefault(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final node = getHavenDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int ?? 0;
|
||||
|
||||
|
@ -310,25 +297,21 @@ Future<void> changeHavenCurrentNodeToDefault(
|
|||
}
|
||||
|
||||
Future<void> replaceDefaultNode(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
const nodesForReplace = <String>[
|
||||
'xmr-node-uk.cakewallet.com:18081',
|
||||
'eu-node.cakewallet.io:18081',
|
||||
'node.cakewallet.io:18081'
|
||||
];
|
||||
final currentNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final currentNode =
|
||||
nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId);
|
||||
final needToReplace =
|
||||
currentNode == null ? true : nodesForReplace.contains(currentNode.uriRaw);
|
||||
final currentNode = nodes.values.firstWhereOrNull((Node node) => node.key == currentNodeId);
|
||||
final needToReplace = currentNode == null ? true : nodesForReplace.contains(currentNode.uriRaw);
|
||||
|
||||
if (!needToReplace) {
|
||||
return;
|
||||
}
|
||||
|
||||
await changeMoneroCurrentNodeToDefault(
|
||||
sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
await changeMoneroCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
}
|
||||
|
||||
Future<void> updateNodeTypes({required Box<Node> nodes}) async {
|
||||
|
@ -367,14 +350,11 @@ Future<void> addHavenNodeList({required Box<Node> nodes}) async {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> addAddressesForMoneroWallets(
|
||||
Box<WalletInfo> walletInfoSource) async {
|
||||
final moneroWalletsInfo =
|
||||
walletInfoSource.values.where((info) => info.type == WalletType.monero);
|
||||
Future<void> addAddressesForMoneroWallets(Box<WalletInfo> walletInfoSource) async {
|
||||
final moneroWalletsInfo = walletInfoSource.values.where((info) => info.type == WalletType.monero);
|
||||
moneroWalletsInfo.forEach((info) async {
|
||||
try {
|
||||
final walletPath =
|
||||
await pathForWallet(name: info.name, type: WalletType.monero);
|
||||
final walletPath = await pathForWallet(name: info.name, type: WalletType.monero);
|
||||
final addressFilePath = '$walletPath.address.txt';
|
||||
final addressFile = File(addressFilePath);
|
||||
|
||||
|
@ -395,8 +375,7 @@ Future<void> updateDisplayModes(SharedPreferences sharedPreferences) async {
|
|||
final currentBalanceDisplayMode =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey) ?? -1;
|
||||
final balanceDisplayMode = currentBalanceDisplayMode < 2 ? 3 : 2;
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentBalanceDisplayModeKey, balanceDisplayMode);
|
||||
}
|
||||
|
||||
Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
|
||||
|
@ -410,10 +389,9 @@ Future<void> generateBackupPassword(FlutterSecureStorage secureStorage) async {
|
|||
await secureStorage.write(key: key, value: password);
|
||||
}
|
||||
|
||||
Future<void> changeTransactionPriorityAndFeeRateKeys(
|
||||
SharedPreferences sharedPreferences) async {
|
||||
final legacyTransactionPriority = sharedPreferences
|
||||
.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy)!;
|
||||
Future<void> changeTransactionPriorityAndFeeRateKeys(SharedPreferences sharedPreferences) async {
|
||||
final legacyTransactionPriority =
|
||||
sharedPreferences.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy)!;
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.moneroTransactionPriority, legacyTransactionPriority);
|
||||
await sharedPreferences.setInt(PreferencesKey.bitcoinTransactionPriority,
|
||||
|
@ -423,10 +401,8 @@ Future<void> changeTransactionPriorityAndFeeRateKeys(
|
|||
Future<void> changeDefaultMoneroNode(
|
||||
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||
const cakeWalletMoneroNodeUriPattern = '.cakewallet.com';
|
||||
final currentMoneroNodeId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final currentMoneroNode =
|
||||
nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId);
|
||||
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final currentMoneroNode = nodeSource.values.firstWhere((node) => node.key == currentMoneroNodeId);
|
||||
final needToReplaceCurrentMoneroNode =
|
||||
currentMoneroNode.uri.toString().contains(cakeWalletMoneroNodeUriPattern);
|
||||
|
||||
|
@ -437,78 +413,64 @@ Future<void> changeDefaultMoneroNode(
|
|||
}
|
||||
});
|
||||
|
||||
final newCakeWalletNode =
|
||||
Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
||||
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
||||
|
||||
await nodeSource.add(newCakeWalletNode);
|
||||
|
||||
if (needToReplaceCurrentMoneroNode) {
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> checkCurrentNodes(
|
||||
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||
final currentMoneroNodeId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
Future<void> checkCurrentNodes(Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||
final currentMoneroNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
|
||||
final currentBitcoinElectrumSeverId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final currentLitecoinElectrumSeverId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final currentHavenNodeId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final currentEthereumNodeId = sharedPreferences
|
||||
.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||
final currentMoneroNode = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentMoneroNodeId);
|
||||
final currentBitcoinElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentBitcoinElectrumSeverId);
|
||||
final currentLitecoinElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentLitecoinElectrumSeverId);
|
||||
final currentHavenNodeServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentHavenNodeId);
|
||||
final currentEthereumNodeServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.key == currentEthereumNodeId);
|
||||
final currentLitecoinElectrumSeverId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final currentHavenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final currentEthereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||
final currentMoneroNode =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentMoneroNodeId);
|
||||
final currentBitcoinElectrumServer =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentBitcoinElectrumSeverId);
|
||||
final currentLitecoinElectrumServer =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentLitecoinElectrumSeverId);
|
||||
final currentHavenNodeServer =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentHavenNodeId);
|
||||
final currentEthereumNodeServer =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentEthereumNodeId);
|
||||
|
||||
if (currentMoneroNode == null) {
|
||||
final newCakeWalletNode =
|
||||
Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
||||
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
||||
await nodeSource.add(newCakeWalletNode);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int);
|
||||
}
|
||||
|
||||
if (currentBitcoinElectrumServer == null) {
|
||||
final cakeWalletElectrum =
|
||||
Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin);
|
||||
final cakeWalletElectrum = Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin);
|
||||
await nodeSource.add(cakeWalletElectrum);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey,
|
||||
cakeWalletElectrum.key as int);
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletElectrum.key as int);
|
||||
}
|
||||
|
||||
if (currentLitecoinElectrumServer == null) {
|
||||
final cakeWalletElectrum =
|
||||
Node(uri: cakeWalletLitecoinElectrumUri, type: WalletType.litecoin);
|
||||
final cakeWalletElectrum = Node(uri: cakeWalletLitecoinElectrumUri, type: WalletType.litecoin);
|
||||
await nodeSource.add(cakeWalletElectrum);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentLitecoinElectrumSererIdKey,
|
||||
cakeWalletElectrum.key as int);
|
||||
PreferencesKey.currentLitecoinElectrumSererIdKey, cakeWalletElectrum.key as int);
|
||||
}
|
||||
|
||||
if (currentHavenNodeServer == null) {
|
||||
final node = Node(uri: havenDefaultNodeUri, type: WalletType.haven);
|
||||
await nodeSource.add(node);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentHavenNodeIdKey, node.key as int);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentHavenNodeIdKey, node.key as int);
|
||||
}
|
||||
|
||||
if (currentEthereumNodeServer == null) {
|
||||
final node = Node(uri: ethereumDefaultNodeUri, type: WalletType.ethereum);
|
||||
await nodeSource.add(node);
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentEthereumNodeIdKey, node.key as int);
|
||||
await sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, node.key as int);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,31 +478,27 @@ Future<void> resetBitcoinElectrumServer(
|
|||
Box<Node> nodeSource, SharedPreferences sharedPreferences) async {
|
||||
final currentElectrumSeverId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
final oldElectrumServer = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.uri.toString().contains('electrumx.cakewallet.com'));
|
||||
var cakeWalletNode = nodeSource.values.firstWhereOrNull(
|
||||
(node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
|
||||
final oldElectrumServer = nodeSource.values
|
||||
.firstWhereOrNull((node) => node.uri.toString().contains('electrumx.cakewallet.com'));
|
||||
var cakeWalletNode = nodeSource.values
|
||||
.firstWhereOrNull((node) => node.uriRaw.toString() == cakeWalletBitcoinElectrumUri);
|
||||
|
||||
if (cakeWalletNode == null) {
|
||||
cakeWalletNode =
|
||||
Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin);
|
||||
cakeWalletNode = Node(uri: cakeWalletBitcoinElectrumUri, type: WalletType.bitcoin);
|
||||
await nodeSource.add(cakeWalletNode);
|
||||
}
|
||||
|
||||
if (currentElectrumSeverId == oldElectrumServer?.key) {
|
||||
await sharedPreferences.setInt(
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey,
|
||||
cakeWalletNode.key as int);
|
||||
PreferencesKey.currentBitcoinElectrumSererIdKey, cakeWalletNode.key as int);
|
||||
}
|
||||
|
||||
await oldElectrumServer?.delete();
|
||||
}
|
||||
|
||||
Future<void> changeDefaultHavenNode(
|
||||
Box<Node> nodeSource) async {
|
||||
Future<void> changeDefaultHavenNode(Box<Node> nodeSource) async {
|
||||
const previousHavenDefaultNodeUri = 'vault.havenprotocol.org:443';
|
||||
final havenNodes = nodeSource.values.where(
|
||||
(node) => node.uriRaw == previousHavenDefaultNodeUri);
|
||||
final havenNodes = nodeSource.values.where((node) => node.uriRaw == previousHavenDefaultNodeUri);
|
||||
havenNodes.forEach((node) async {
|
||||
node.uriRaw = havenDefaultNodeUri;
|
||||
await node.save();
|
||||
|
@ -553,8 +511,8 @@ Future<void> migrateExchangeStatus(SharedPreferences sharedPreferences) async {
|
|||
return;
|
||||
}
|
||||
|
||||
await sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, isExchangeDisabled
|
||||
? ExchangeApiMode.disabled.raw : ExchangeApiMode.enabled.raw);
|
||||
await sharedPreferences.setInt(PreferencesKey.exchangeStatusKey,
|
||||
isExchangeDisabled ? ExchangeApiMode.disabled.raw : ExchangeApiMode.enabled.raw);
|
||||
|
||||
await sharedPreferences.remove(PreferencesKey.disableExchangeKey);
|
||||
}
|
||||
|
@ -569,10 +527,26 @@ Future<void> addEthereumNodeList({required Box<Node> nodes}) async {
|
|||
}
|
||||
|
||||
Future<void> changeEthereumCurrentNodeToDefault(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes}) async {
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final node = getEthereumDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int? ?? 0;
|
||||
|
||||
await sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, nodeId);
|
||||
}
|
||||
|
||||
Future<void> addNanoNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultNanoNodes();
|
||||
for (var node in nodeList) {
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changeNanoCurrentNodeToDefault(
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final node = getNanoDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int? ?? 0;
|
||||
|
||||
await sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, nodeId);
|
||||
}
|
||||
|
|
|
@ -21,13 +21,12 @@ Future<List<Node>> loadDefaultNodes() async {
|
|||
}
|
||||
|
||||
Future<List<Node>> loadBitcoinElectrumServerList() async {
|
||||
final serverListRaw =
|
||||
await rootBundle.loadString('assets/bitcoin_electrum_server_list.yml');
|
||||
final serverListRaw = await rootBundle.loadString('assets/bitcoin_electrum_server_list.yml');
|
||||
final loadedServerList = loadYaml(serverListRaw) as YamlList;
|
||||
final serverList = <Node>[];
|
||||
|
||||
for (final raw in loadedServerList) {
|
||||
if (raw is Map) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.bitcoin;
|
||||
serverList.add(node);
|
||||
|
@ -38,8 +37,7 @@ Future<List<Node>> loadBitcoinElectrumServerList() async {
|
|||
}
|
||||
|
||||
Future<List<Node>> loadLitecoinElectrumServerList() async {
|
||||
final serverListRaw =
|
||||
await rootBundle.loadString('assets/litecoin_electrum_server_list.yml');
|
||||
final serverListRaw = await rootBundle.loadString('assets/litecoin_electrum_server_list.yml');
|
||||
final loadedServerList = loadYaml(serverListRaw) as YamlList;
|
||||
final serverList = <Node>[];
|
||||
|
||||
|
@ -66,7 +64,7 @@ Future<List<Node>> loadDefaultHavenNodes() async {
|
|||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
|
@ -94,7 +92,7 @@ Future<List<Node>> loadDefaultNanoNodes() async {
|
|||
for (final raw in loadedNodes) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
node.type = WalletType.ethereum;
|
||||
node.type = WalletType.nano;
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
@ -107,12 +105,13 @@ Future resetToDefault(Box<Node> nodeSource) async {
|
|||
final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
|
||||
final litecoinElectrumServerList = await loadLitecoinElectrumServerList();
|
||||
final havenNodes = await loadDefaultHavenNodes();
|
||||
final ethereumNodes = await loadDefaultEthereumNodes();
|
||||
final nanoNodes = await loadDefaultNanoNodes();
|
||||
final nodes =
|
||||
moneroNodes +
|
||||
final nodes = moneroNodes +
|
||||
bitcoinElectrumServerList +
|
||||
litecoinElectrumServerList +
|
||||
havenNodes +
|
||||
ethereumNodes +
|
||||
nanoNodes;
|
||||
|
||||
await nodeSource.clear();
|
||||
|
|
|
@ -6,6 +6,7 @@ class PreferencesKey {
|
|||
static const currentLitecoinElectrumSererIdKey = 'current_node_id_ltc';
|
||||
static const currentHavenNodeIdKey = 'current_node_id_xhv';
|
||||
static const currentEthereumNodeIdKey = 'current_node_id_eth';
|
||||
static const currentNanoNodeIdKey = 'current_node_id_nano';
|
||||
static const currentFiatCurrencyKey = 'current_fiat_currency';
|
||||
static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
|
||||
static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
|
||||
|
|
|
@ -141,7 +141,7 @@ Future<void> main() async {
|
|||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
initialMigrationVersion: 21);
|
||||
initialMigrationVersion: 22);
|
||||
runApp(App());
|
||||
}, (error, stackTrace) async {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||
|
|
|
@ -47,6 +47,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||
final ethereumIcon = Image.asset('assets/images/eth_icon.png', height: 24, width: 24);
|
||||
final nanoIcon = Image.asset('assets/images/nano_icon.png', height: 24, width: 24);
|
||||
final scrollController = ScrollController();
|
||||
final double tileHeight = 60;
|
||||
Flushbar<void>? _progressBar;
|
||||
|
@ -205,6 +206,8 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
return havenIcon;
|
||||
case WalletType.ethereum:
|
||||
return ethereumIcon;
|
||||
case WalletType.nano:
|
||||
return nanoIcon;
|
||||
default:
|
||||
return nonWalletTypeIcon;
|
||||
}
|
||||
|
|
|
@ -431,11 +431,13 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||
final moneroNode = nodeSource.get(nodeId);
|
||||
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||
final havenNode = nodeSource.get(havenNodeId);
|
||||
final ethereumNode = nodeSource.get(ethereumNodeId);
|
||||
final nanoNode = nodeSource.get(nanoNodeId);
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
final deviceName = await _getDeviceName() ?? '';
|
||||
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
|
||||
|
@ -462,6 +464,10 @@ abstract class SettingsStoreBase with Store {
|
|||
nodes[WalletType.ethereum] = ethereumNode;
|
||||
}
|
||||
|
||||
if (nanoNode != null) {
|
||||
nodes[WalletType.nano] = nanoNode;
|
||||
}
|
||||
|
||||
return SettingsStore(
|
||||
sharedPreferences: sharedPreferences,
|
||||
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
|
||||
|
@ -577,11 +583,13 @@ abstract class SettingsStoreBase with Store {
|
|||
sharedPreferences.getInt(PreferencesKey.currentLitecoinElectrumSererIdKey);
|
||||
final havenNodeId = sharedPreferences.getInt(PreferencesKey.currentHavenNodeIdKey);
|
||||
final ethereumNodeId = sharedPreferences.getInt(PreferencesKey.currentEthereumNodeIdKey);
|
||||
final nanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||
final moneroNode = nodeSource.get(nodeId);
|
||||
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||
final havenNode = nodeSource.get(havenNodeId);
|
||||
final ethereumNode = nodeSource.get(ethereumNodeId);
|
||||
final nanoNode = nodeSource.get(nanoNodeId);
|
||||
|
||||
if (moneroNode != null) {
|
||||
nodes[WalletType.monero] = moneroNode;
|
||||
|
@ -602,6 +610,10 @@ abstract class SettingsStoreBase with Store {
|
|||
if (ethereumNode != null) {
|
||||
nodes[WalletType.ethereum] = ethereumNode;
|
||||
}
|
||||
|
||||
if (nanoNode != null) {
|
||||
nodes[WalletType.nano] = nanoNode;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _saveCurrentNode(Node node, WalletType walletType) async {
|
||||
|
@ -623,6 +635,9 @@ abstract class SettingsStoreBase with Store {
|
|||
case WalletType.ethereum:
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, node.key as int);
|
||||
break;
|
||||
case WalletType.nano:
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentNanoNodeIdKey, node.key as int);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,9 @@ abstract class NodeListViewModelBase with Store {
|
|||
case WalletType.haven:
|
||||
node = getHavenDefaultNode(nodes: _nodeSource)!;
|
||||
break;
|
||||
case WalletType.ethereum:
|
||||
node = getEthereumDefaultNode(nodes: _nodeSource)!;
|
||||
break;
|
||||
case WalletType.nano:
|
||||
node = getNanoDefaultNode(nodes: _nodeSource)!;
|
||||
break;
|
||||
|
|
|
@ -110,6 +110,23 @@ class EthereumURI extends PaymentURI {
|
|||
}
|
||||
}
|
||||
|
||||
class NanoURI extends PaymentURI {
|
||||
NanoURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
print(address);
|
||||
var base = 'nano:' + address;
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WalletAddressListViewModelBase with Store {
|
||||
WalletAddressListViewModelBase({
|
||||
required AppStore appStore,
|
||||
|
@ -172,6 +189,10 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
return EthereumURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
||||
if (_wallet.type == WalletType.nano) {
|
||||
return NanoURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ flutter:
|
|||
- assets/bitcoin_electrum_server_list.yml
|
||||
- assets/litecoin_electrum_server_list.yml
|
||||
- assets/ethereum_server_list.yml
|
||||
- assets/nano_node_list.yml
|
||||
- assets/text/
|
||||
- assets/faq/
|
||||
- assets/animation/
|
||||
|
|
Loading…
Reference in a new issue