diff --git a/cw_core/lib/sec_random_native.dart b/cw_core/lib/sec_random_native.dart index 2011602bf..53ca7c942 100644 --- a/cw_core/lib/sec_random_native.dart +++ b/cw_core/lib/sec_random_native.dart @@ -14,8 +14,14 @@ Future secRandom(int count) async { final rng = Random.secure(); return Uint8List.fromList(List.generate(count, (_) => rng.nextInt(byteSize))); } - return await utils.invokeMethod('sec_random', {'count': count}) ?? Uint8List.fromList([]); - } on PlatformException catch (_) { - return Uint8List.fromList([]); + final bytes = await utils.invokeMethod('sec_random', {'count': count}); + if (bytes == null || bytes.length != count) { + throw StateError('sec_random returned ${bytes?.length ?? 0} bytes, expected $count'); + } + return bytes; + } on PlatformException catch (e) { + // Never fail open: an entropy source that cannot deliver must throw, + // not hand back an empty buffer for key material. + throw StateError('sec_random platform call failed: ${e.message}'); } } diff --git a/cw_wownero/lib/wownero_wallet.dart b/cw_wownero/lib/wownero_wallet.dart index 08b7e6541..2753daabc 100644 --- a/cw_wownero/lib/wownero_wallet.dart +++ b/cw_wownero/lib/wownero_wallet.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:ffi'; import 'dart:io'; import 'dart:isolate'; @@ -223,12 +224,38 @@ abstract class WowneroWalletBase wownero_wallet.setTrustedDaemon(node.trusted); syncStatus = ConnectedSyncStatus(); + unawaited(_updateBaseFeeEstimate(node)); } catch (e) { syncStatus = FailedSyncStatus(); printV(e); } } + Future _updateBaseFeeEstimate(Node node) async { + try { + final rpcUri = node.isSSL + ? Uri.https(node.uri.authority, '/json_rpc') + : Uri.http(node.uri.authority, '/json_rpc'); + final client = ProxyWrapper().getHttpIOClient(); + final response = await client + .post(rpcUri, + headers: {'Content-Type': 'application/json'}, + body: json.encode({'jsonrpc': '2.0', 'id': '0', 'method': 'get_fee_estimate'})) + .timeout(const Duration(seconds: 15)); + + if (response.statusCode != 200) return; + + final result = + (json.decode(response.body) as Map)['result'] as Map?; + final feePerByte = result?['fee'] as int?; + if (feePerByte != null && feePerByte > 0) { + _cachedBaseFeePerByte = feePerByte; + } + } catch (e) { + printV('get_fee_estimate failed, keeping fallback fee table: $e'); + } + } + @override Future startSync() async { try { @@ -352,11 +379,26 @@ abstract class WowneroWalletBase return PendingWowneroTransaction(pendingTransactionDescription); } + // Base fee per byte in atomic units, fetched from the connected daemon's + // get_fee_estimate RPC. Null until the first successful fetch. + int? _cachedBaseFeePerByte; + + // Typical 2-in/2-out ring-22 transaction weight. Only used for the + // pre-confirmation estimate; the real fee comes from wallet2 when the + // transaction is built. + static const _estimatedTxWeightBytes = 2300; + @override int calculateEstimatedFee(TransactionPriority priority, int? amount) { - // FIXME: hardcoded value; - if (priority is MoneroTransactionPriority) { + final baseFeePerByte = _cachedBaseFeePerByte; + if (baseFeePerByte != null) { + return baseFeePerByte * _estimatedTxWeightBytes * _feeMultiplier(priority); + } + + // Fallback while no daemon estimate is available yet. Inherited from + // upstream and calibrated for XMR, not WOW — kept only so the send + // screen shows something before get_fee_estimate returns. switch (priority) { case MoneroTransactionPriority.slow: return 24590000; @@ -374,6 +416,23 @@ abstract class WowneroWalletBase return 0; } + int _feeMultiplier(MoneroTransactionPriority priority) { + switch (priority) { + case MoneroTransactionPriority.slow: + return 1; + case MoneroTransactionPriority.automatic: + return 5; + case MoneroTransactionPriority.medium: + return 10; + case MoneroTransactionPriority.fast: + return 25; + case MoneroTransactionPriority.fastest: + return 1000; + default: + return 5; + } + } + @override Future save() async { await walletAddresses.updateUsedSubaddress(); diff --git a/ios/Runner/InfoBase.plist b/ios/Runner/InfoBase.plist index b26180cb1..58112f882 100644 --- a/ios/Runner/InfoBase.plist +++ b/ios/Runner/InfoBase.plist @@ -38,10 +38,6 @@ hashbags - - CFBundleTypeRole - Editor - CFBundleTypeRole Editor diff --git a/lib/entities/node_list.dart b/lib/entities/node_list.dart index b42bc5054..0bce9b338 100644 --- a/lib/entities/node_list.dart +++ b/lib/entities/node_list.dart @@ -82,6 +82,7 @@ Future> loadDefaultNanoPowNodes() async { } Future resetToDefault(Box nodeSource) async { + final wowneroNodes = await loadDefaultNodes(WalletType.wownero); final moneroNodes = await loadDefaultNodes(WalletType.monero); final bitcoinElectrumServerList = await loadDefaultNodes(WalletType.bitcoin); final litecoinElectrumServerList = await loadDefaultNodes(WalletType.litecoin); @@ -94,7 +95,8 @@ Future resetToDefault(Box nodeSource) async { final arbitrumNodes = await loadDefaultNodes(WalletType.arbitrum); final bscNodes = await loadDefaultNodes(WalletType.bsc); - final nodes = moneroNodes + + final nodes = wowneroNodes + + moneroNodes + bitcoinElectrumServerList + litecoinElectrumServerList + ethereumNodes + diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index f436986e9..8a0a58024 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -389,7 +389,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo case WalletType.monero: return monero!.getCurrentAccount(wallet).label; case WalletType.wownero: - wownero!.getCurrentAccount(wallet).label; + return wownero!.getCurrentAccount(wallet).label; default: return ''; } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 1edccdd74..9f09512b3 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -38,6 +38,7 @@ dependencies: flutter_local_authentication: git: url: https://github.com/cake-tech/flutter_local_authentication + ref: 75c8681ebef62398a87c8ae0cccb7cfddffa9734 package_info_plus: ^8.0.1 devicelocale: 0.8.1 auto_size_text: ^3.0.0 @@ -82,7 +83,7 @@ dependencies: cake_backup: git: url: https://github.com/cake-tech/cake_backup.git - ref: main + ref: 3aba867dcab6737f6707782f5db15d71f303db38 version: 1.0.0 flutter_plugin_android_lifecycle: 2.0.23 path_provider_android: ^2.2.1 @@ -190,6 +191,7 @@ dependency_overrides: bech32: git: url: https://github.com/cake-tech/bech32.git + ref: 05755063b593aa6cca0a4820a318e0ce17de6192 web3dart: git: url: https://github.com/cake-tech/web3dart.git diff --git a/scripts/ios/app_config.sh b/scripts/ios/app_config.sh index ef7c6b28c..10a42c7e8 100755 --- a/scripts/ios/app_config.sh +++ b/scripts/ios/app_config.sh @@ -18,9 +18,6 @@ cp -rf ./ios/Runner/InfoBase.plist ./ios/Runner/Info.plist /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${APP_IOS_VERSION}" ./ios/Runner/Info.plist /usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${APP_IOS_BUILD_NUMBER}" ./ios/Runner/Info.plist -/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLName string ${APP_IOS_TYPE}" ./ios/Runner/Info.plist -/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLSchemes array" ./ios/Runner/Info.plist -/usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLSchemes: string ${APP_IOS_TYPE}" ./ios/Runner/Info.plist universal_sed "s/PRODUCT_BUNDLE_IDENTIFIER = .*;/PRODUCT_BUNDLE_IDENTIFIER = $APP_IOS_BUNDLE_ID;/g" ./ios/Runner.xcodeproj/project.pbxproj CONFIG_ARGS=""