mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
finalizing wownero
This commit is contained in:
parent
2ad76de4be
commit
f48023b60c
15 changed files with 205 additions and 25 deletions
|
@ -61,17 +61,17 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile file(keystoreProperties['storeFile'])
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
// signingConfigs {
|
||||
// release {
|
||||
// keyAlias keystoreProperties['keyAlias']
|
||||
// keyPassword keystoreProperties['keyPassword']
|
||||
// storeFile file(keystoreProperties['storeFile'])
|
||||
// storePassword keystoreProperties['storePassword']
|
||||
// }
|
||||
// }
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
// signingConfig signingConfigs.release
|
||||
|
||||
shrinkResources false
|
||||
minifyEnabled false
|
||||
|
|
|
@ -91,6 +91,9 @@
|
|||
<data android:scheme="tron" />
|
||||
<data android:scheme="tron-wallet" />
|
||||
<data android:scheme="tron_wallet" />
|
||||
<data android:scheme="wownero" />
|
||||
<data android:scheme="wownero-wallet" />
|
||||
<data android:scheme="wownero_wallet" />
|
||||
</intent-filter>
|
||||
<!-- nano-gpt link scheme -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
|
|
|
@ -1,2 +1,8 @@
|
|||
-
|
||||
uri: electrum.cakewallet.com:50002
|
||||
uri: electrum.cakewallet.com:50002
|
||||
useSSL: true
|
||||
-
|
||||
uri: btc-electrum.cakewallet.com:50002
|
||||
isDefault: true
|
||||
-
|
||||
uri: electrs.cakewallet.com:50001
|
||||
|
|
|
@ -214,7 +214,7 @@ Now you can run the codebase and successfully create a wallet for type walletX s
|
|||
**Restore Wallet**
|
||||
- Go to `lib/core/seed_validator.dart`
|
||||
- In the `getWordList` method, add a case to handle `WalletType.walletx` which would return the word list to be used to validate the passed in seeds.
|
||||
- Next, go to `lib/restore_view_model.dart`
|
||||
- Next, go to `lib/wallet_restore_view_model.dart`
|
||||
- Modify the `hasRestoreFromPrivateKey` to reflect if walletx supports restore from Key
|
||||
- Add a switch case to handle the various restore modes that walletX supports
|
||||
- Modify the `getCredential` method to handle the restore flows for `WalletType.walletx`
|
||||
|
|
|
@ -200,7 +200,7 @@
|
|||
<string>solana-wallet</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
|
@ -220,6 +220,26 @@
|
|||
<string>tron-wallet</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>wownero</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>wownero</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>wownero-wallet</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>wownero-wallet</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
|
|
|
@ -139,6 +139,7 @@ class AddressValidator extends TextValidator {
|
|||
|
||||
switch (type) {
|
||||
case CryptoCurrency.xmr:
|
||||
case CryptoCurrency.wow:
|
||||
return null;
|
||||
case CryptoCurrency.ada:
|
||||
return null;
|
||||
|
@ -266,6 +267,7 @@ class AddressValidator extends TextValidator {
|
|||
static String? getAddressFromStringPattern(CryptoCurrency type) {
|
||||
switch (type) {
|
||||
case CryptoCurrency.xmr:
|
||||
case CryptoCurrency.wow:
|
||||
return '([^0-9a-zA-Z]|^)4[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)';
|
||||
|
|
|
@ -229,6 +229,10 @@ Future<void> defaultSettingsMigration(
|
|||
case 34:
|
||||
await _addElectRsNode(nodes, sharedPreferences);
|
||||
break;
|
||||
case 36:
|
||||
await addWowneroNodeList(nodes: nodes);
|
||||
await changeWowneroCurrentNodeToDefault(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -488,9 +492,23 @@ Node? getTronDefaultNode({required Box<Node> nodes}) {
|
|||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.tron);
|
||||
}
|
||||
|
||||
Node? getWowneroDefaultNode({required Box<Node> nodes}) {
|
||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == wowneroDefaultNodeUri) ??
|
||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.wownero);
|
||||
Node getWowneroDefaultNode({required Box<Node> nodes}) {
|
||||
final timeZone = DateTime.now().timeZoneOffset.inHours;
|
||||
var nodeUri = '';
|
||||
|
||||
if (timeZone >= 1) {
|
||||
// Eurasia
|
||||
nodeUri = 'node2.monerodevs.org.lol:34568';
|
||||
} else if (timeZone <= -4) {
|
||||
// America
|
||||
nodeUri = 'node3.monerodevs.org:34568';
|
||||
}
|
||||
|
||||
try {
|
||||
return nodes.values.firstWhere((Node node) => node.uriRaw == nodeUri);
|
||||
} catch (_) {
|
||||
return nodes.values.first;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> insecureStorageMigration({
|
||||
|
@ -1021,6 +1039,23 @@ Future<void> changeEthereumCurrentNodeToDefault(
|
|||
await sharedPreferences.setInt(PreferencesKey.currentEthereumNodeIdKey, nodeId);
|
||||
}
|
||||
|
||||
Future<void> addWowneroNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultWowneroNodes();
|
||||
for (var node in nodeList) {
|
||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == node.uriRaw) == null) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> changeWowneroCurrentNodeToDefault(
|
||||
{required SharedPreferences sharedPreferences, required Box<Node> nodes}) async {
|
||||
final node = getWowneroDefaultNode(nodes: nodes);
|
||||
final nodeId = node?.key as int? ?? 0;
|
||||
|
||||
await sharedPreferences.setInt(PreferencesKey.currentWowneroNodeIdKey, nodeId);
|
||||
}
|
||||
|
||||
Future<void> addNanoNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultNanoNodes();
|
||||
for (var node in nodeList) {
|
||||
|
|
|
@ -183,6 +183,23 @@ Future<List<Node>> loadDefaultTronNodes() async {
|
|||
return nodes;
|
||||
}
|
||||
|
||||
Future<List<Node>> loadDefaultWowneroNodes() async {
|
||||
final nodesRaw = await rootBundle.loadString('assets/wownero_node_list.yml');
|
||||
final loadedNodes = loadYaml(nodesRaw) as YamlList;
|
||||
final nodes = <Node>[];
|
||||
|
||||
for (final raw in loadedNodes) {
|
||||
if (raw is Map) {
|
||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||
|
||||
node.type = WalletType.wownero;
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||
final moneroNodes = await loadDefaultNodes();
|
||||
final bitcoinElectrumServerList = await loadBitcoinElectrumServerList();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io' show Platform;
|
||||
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
|
@ -42,7 +41,6 @@ import 'package:hive/hive.dart';
|
|||
import 'package:cw_core/root_dir.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cw_core/window_size.dart';
|
||||
import 'package:monero/monero.dart' as monero_dart;
|
||||
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
final rootKey = GlobalKey<RootState>();
|
||||
|
@ -205,7 +203,7 @@ Future<void> initializeAppConfigs() async {
|
|||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
initialMigrationVersion: 34,
|
||||
initialMigrationVersion: 36,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ abstract class BalanceViewModelBase with Store {
|
|||
String get availableBalanceLabel {
|
||||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
case WalletType.haven:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
|
@ -142,6 +143,7 @@ abstract class BalanceViewModelBase with Store {
|
|||
String get additionalBalanceLabel {
|
||||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
case WalletType.haven:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
|
|
|
@ -75,6 +75,15 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
|||
viewKey: restoreWallet.viewKey ?? '',
|
||||
spendKey: restoreWallet.spendKey ?? '',
|
||||
height: restoreWallet.height ?? 0);
|
||||
case WalletType.wownero:
|
||||
return wownero!.createWowneroRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: 'English',
|
||||
address: restoreWallet.address ?? '',
|
||||
viewKey: restoreWallet.viewKey ?? '',
|
||||
spendKey: restoreWallet.spendKey ?? '',
|
||||
height: restoreWallet.height ?? 0);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
||||
|
|
|
@ -36,6 +36,9 @@ class WalletRestoreFromQRCode {
|
|||
'tron': WalletType.tron,
|
||||
'tron-wallet': WalletType.tron,
|
||||
'tron_wallet': WalletType.tron,
|
||||
'wownero': WalletType.wownero,
|
||||
'wownero-wallet': WalletType.wownero,
|
||||
'wownero_wallet': WalletType.wownero,
|
||||
};
|
||||
|
||||
static bool _containsAssetSpecifier(String code) => _extractWalletType(code) != null;
|
||||
|
@ -57,7 +60,9 @@ class WalletRestoreFromQRCode {
|
|||
RegExp _getPattern(int wordCount) =>
|
||||
RegExp(r'(?<=\W|^)((?:\w+\s+){' + (wordCount - 1).toString() + r'}\w+)(?=\W|$)');
|
||||
|
||||
List<int> patternCounts = walletType == WalletType.monero ? [25, 16, 14, 13] : [24, 18, 12];
|
||||
List<int> patternCounts = walletType == WalletType.monero || walletType == WalletType.wownero
|
||||
? [25, 16, 14, 13]
|
||||
: [24, 18, 12];
|
||||
|
||||
for (final count in patternCounts) {
|
||||
final pattern = _getPattern(count);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -76,7 +77,7 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
_addTronListItems(tx, dateFormat);
|
||||
break;
|
||||
case WalletType.wownero:
|
||||
// _addWowneroListItems(tx, dateFormat);
|
||||
_addWowneroListItems(tx, dateFormat);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -169,7 +170,9 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
return 'https://solscan.io/tx/${txId}';
|
||||
case WalletType.tron:
|
||||
return 'https://tronscan.org/#/transaction/${txId}';
|
||||
default:
|
||||
case WalletType.wownero:
|
||||
return 'https://explore.wownero.com/tx/${txId}';
|
||||
case WalletType.none:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +200,9 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
return S.current.view_transaction_on + 'solscan.io';
|
||||
case WalletType.tron:
|
||||
return S.current.view_transaction_on + 'tronscan.org';
|
||||
default:
|
||||
case WalletType.wownero:
|
||||
return S.current.view_transaction_on + 'Wownero.com';
|
||||
case WalletType.none:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
@ -442,4 +447,44 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled
|
||||
? ''
|
||||
: sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||
|
||||
void _addWowneroListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||
final key = tx.additionalInfo['key'] as String?;
|
||||
final accountIndex = tx.additionalInfo['accountIndex'] as int;
|
||||
final addressIndex = tx.additionalInfo['addressIndex'] as int;
|
||||
final feeFormatted = tx.feeFormatted();
|
||||
final _items = [
|
||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
||||
StandartListItem(title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
|
||||
if (feeFormatted != null)
|
||||
StandartListItem(title: S.current.transaction_details_fee, value: feeFormatted),
|
||||
if (key?.isNotEmpty ?? false) StandartListItem(title: S.current.transaction_key, value: key!),
|
||||
];
|
||||
|
||||
if (tx.direction == TransactionDirection.incoming) {
|
||||
try {
|
||||
final address = wownero!.getTransactionAddress(wallet, accountIndex, addressIndex);
|
||||
final label = wownero!.getSubaddressLabel(wallet, accountIndex, addressIndex);
|
||||
|
||||
if (address.isNotEmpty) {
|
||||
isRecipientAddressShown = true;
|
||||
_items.add(StandartListItem(
|
||||
title: S.current.transaction_details_recipient_address,
|
||||
value: address,
|
||||
));
|
||||
}
|
||||
|
||||
if (label.isNotEmpty) {
|
||||
_items.add(StandartListItem(title: S.current.address_label, value: label));
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
items.addAll(_items);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:cake_wallet/utils/list_item.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_account_list_header.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_header.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/amount_converter.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -191,6 +192,22 @@ class TronURI extends PaymentURI {
|
|||
}
|
||||
}
|
||||
|
||||
class WowneroURI extends PaymentURI {
|
||||
WowneroURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'wownero:' + address;
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?tx_amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
|
||||
WalletAddressListViewModelBase({
|
||||
required AppStore appStore,
|
||||
|
@ -293,6 +310,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
|||
return TronURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.wownero) {
|
||||
return WowneroURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
|
||||
|
@ -409,6 +430,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
|||
addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.wownero) {
|
||||
final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
|
||||
final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
|
||||
final isPrimary = subaddress == primaryAddress;
|
||||
|
||||
return WalletAddressListItem(
|
||||
id: subaddress.id,
|
||||
isPrimary: isPrimary,
|
||||
name: subaddress.label,
|
||||
address: subaddress.address);
|
||||
});
|
||||
addressList.addAll(addressItems);
|
||||
}
|
||||
|
||||
if (searchText.isNotEmpty) {
|
||||
return ObservableList.of(addressList.where((item) {
|
||||
if (item is WalletAddressListItem) {
|
||||
|
|
|
@ -29,8 +29,10 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
{required WalletType type})
|
||||
: hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||
: hasSeedLanguageSelector =
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
|
||||
hasBlockchainHeightLanguageSelector =
|
||||
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
|
||||
hasRestoreFromPrivateKey = type == WalletType.ethereum ||
|
||||
type == WalletType.polygon ||
|
||||
type == WalletType.nano ||
|
||||
|
@ -112,6 +114,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
|
||||
name: name, mnemonic: seed, password: password);
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return nano!.createNanoRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: seed,
|
||||
|
@ -143,7 +146,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
password: password,
|
||||
height: height,
|
||||
);
|
||||
default:
|
||||
case WalletType.none:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue