mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 17:57:40 +00:00
commit
57e1818586
25 changed files with 1243 additions and 2262 deletions
|
@ -22,10 +22,10 @@ Highlights include:
|
||||||
- The only OS supported for building is Ubuntu 20.04
|
- The only OS supported for building is Ubuntu 20.04
|
||||||
- A machine with at least 100 GB of Storage
|
- A machine with at least 100 GB of Storage
|
||||||
|
|
||||||
The following prerequisities can be installed with the setup script `scripts/setup.sh` or manually as described below:
|
The following prerequisites can be installed with the setup script `scripts/setup.sh` or manually as described below:
|
||||||
|
|
||||||
- Flutter 3.3.4 [(install manually or with git, do not install with snap)](https://docs.flutter.dev/get-started/install)
|
- Flutter 3.7.6 [(install manually or with git, do not install with snap)](https://docs.flutter.dev/get-started/install)
|
||||||
- Dart SDK Requirement (>=2.17.0, up until <3.0.0)
|
- Dart SDK Requirement (>=2.19.0, up until <3.0.0) (normally included with a flutter install)
|
||||||
- Android setup ([Android Studio](https://developer.android.com/studio) and subsequent dependencies)
|
- Android setup ([Android Studio](https://developer.android.com/studio) and subsequent dependencies)
|
||||||
|
|
||||||
### Scripted setup
|
### Scripted setup
|
||||||
|
|
|
@ -21,6 +21,6 @@
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>10.0</string>
|
<string>15.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
platform :ios, '10.0'
|
platform :ios, '15.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
|
@ -439,7 +439,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
@ -574,7 +574,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
@ -624,7 +624,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|
21
lib/models/signing_data.dart
Normal file
21
lib/models/signing_data.dart
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:bitcoindart/bitcoindart.dart';
|
||||||
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
||||||
|
|
||||||
|
class SigningData {
|
||||||
|
SigningData({
|
||||||
|
required this.derivePathType,
|
||||||
|
required this.utxo,
|
||||||
|
this.output,
|
||||||
|
this.keyPair,
|
||||||
|
this.redeemScript,
|
||||||
|
});
|
||||||
|
|
||||||
|
final DerivePathType derivePathType;
|
||||||
|
final UTXO utxo;
|
||||||
|
Uint8List? output;
|
||||||
|
ECPair? keyPair;
|
||||||
|
Uint8List? redeemScript;
|
||||||
|
}
|
|
@ -146,16 +146,58 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
|
|
||||||
_updatePreviewButtonState(_address, _amountToSend);
|
_updatePreviewButtonState(_address, _amountToSend);
|
||||||
|
|
||||||
// if (_amountToSend == null) {
|
_cryptoAmountChangedFeeUpdateTimer?.cancel();
|
||||||
// setState(() {
|
_cryptoAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () {
|
||||||
// _calculateFeesFuture = calculateFees(0);
|
if (coin != Coin.epicCash && !_baseFocus.hasFocus) {
|
||||||
// });
|
setState(() {
|
||||||
// } else {
|
_calculateFeesFuture = calculateFees(
|
||||||
// setState(() {
|
_amountToSend == null
|
||||||
// _calculateFeesFuture =
|
? 0
|
||||||
// calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
|
: Format.decimalAmountToSatoshis(
|
||||||
// });
|
_amountToSend!,
|
||||||
// }
|
coin,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final updateFeesTimerDuration = const Duration(milliseconds: 500);
|
||||||
|
|
||||||
|
Timer? _cryptoAmountChangedFeeUpdateTimer;
|
||||||
|
Timer? _baseAmountChangedFeeUpdateTimer;
|
||||||
|
|
||||||
|
void _baseAmountChanged() {
|
||||||
|
_baseAmountChangedFeeUpdateTimer?.cancel();
|
||||||
|
_baseAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () {
|
||||||
|
if (coin != Coin.epicCash && !_cryptoFocus.hasFocus) {
|
||||||
|
setState(() {
|
||||||
|
_calculateFeesFuture = calculateFees(
|
||||||
|
_amountToSend == null
|
||||||
|
? 0
|
||||||
|
: Format.decimalAmountToSatoshis(
|
||||||
|
_amountToSend!,
|
||||||
|
coin,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
int _currentFee = 0;
|
||||||
|
|
||||||
|
void _setCurrentFee(String fee, bool shouldSetState) {
|
||||||
|
final value = Format.decimalAmountToSatoshis(
|
||||||
|
Decimal.parse(fee),
|
||||||
|
coin,
|
||||||
|
);
|
||||||
|
if (shouldSetState) {
|
||||||
|
setState(() => _currentFee = value);
|
||||||
|
} else {
|
||||||
|
_currentFee = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,45 +370,48 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
selectedUTXOs.isEmpty)) {
|
selectedUTXOs.isEmpty)) {
|
||||||
// confirm send all
|
// confirm send all
|
||||||
if (amount == availableBalance) {
|
if (amount == availableBalance) {
|
||||||
final bool? shouldSendAll = await showDialog<bool>(
|
bool? shouldSendAll;
|
||||||
context: context,
|
if (mounted) {
|
||||||
useSafeArea: false,
|
shouldSendAll = await showDialog<bool>(
|
||||||
barrierDismissible: true,
|
context: context,
|
||||||
builder: (context) {
|
useSafeArea: false,
|
||||||
return StackDialog(
|
barrierDismissible: true,
|
||||||
title: "Confirm send all",
|
builder: (context) {
|
||||||
message:
|
return StackDialog(
|
||||||
"You are about to send your entire balance. Would you like to continue?",
|
title: "Confirm send all",
|
||||||
leftButton: TextButton(
|
message:
|
||||||
style: Theme.of(context)
|
"You are about to send your entire balance. Would you like to continue?",
|
||||||
.extension<StackColors>()!
|
leftButton: TextButton(
|
||||||
.getSecondaryEnabledButtonStyle(context),
|
style: Theme.of(context)
|
||||||
child: Text(
|
.extension<StackColors>()!
|
||||||
"Cancel",
|
.getSecondaryEnabledButtonStyle(context),
|
||||||
style: STextStyles.button(context).copyWith(
|
child: Text(
|
||||||
color: Theme.of(context)
|
"Cancel",
|
||||||
.extension<StackColors>()!
|
style: STextStyles.button(context).copyWith(
|
||||||
.accentColorDark),
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.accentColorDark),
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(false);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
onPressed: () {
|
rightButton: TextButton(
|
||||||
Navigator.of(context).pop(false);
|
style: Theme.of(context)
|
||||||
},
|
.extension<StackColors>()!
|
||||||
),
|
.getPrimaryEnabledButtonStyle(context),
|
||||||
rightButton: TextButton(
|
child: Text(
|
||||||
style: Theme.of(context)
|
"Yes",
|
||||||
.extension<StackColors>()!
|
style: STextStyles.button(context),
|
||||||
.getPrimaryEnabledButtonStyle(context),
|
),
|
||||||
child: Text(
|
onPressed: () {
|
||||||
"Yes",
|
Navigator.of(context).pop(true);
|
||||||
style: STextStyles.button(context),
|
},
|
||||||
),
|
),
|
||||||
onPressed: () {
|
);
|
||||||
Navigator.of(context).pop(true);
|
},
|
||||||
},
|
);
|
||||||
),
|
}
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (shouldSendAll == null || shouldSendAll == false) {
|
if (shouldSendAll == null || shouldSendAll == false) {
|
||||||
// cancel preview
|
// cancel preview
|
||||||
|
@ -378,22 +423,24 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
try {
|
try {
|
||||||
bool wasCancelled = false;
|
bool wasCancelled = false;
|
||||||
|
|
||||||
unawaited(
|
if (mounted) {
|
||||||
showDialog<dynamic>(
|
unawaited(
|
||||||
context: context,
|
showDialog<void>(
|
||||||
useSafeArea: false,
|
context: context,
|
||||||
barrierDismissible: false,
|
useSafeArea: false,
|
||||||
builder: (context) {
|
barrierDismissible: false,
|
||||||
return BuildingTransactionDialog(
|
builder: (context) {
|
||||||
onCancel: () {
|
return BuildingTransactionDialog(
|
||||||
wasCancelled = true;
|
onCancel: () {
|
||||||
|
wasCancelled = true;
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic> txData;
|
Map<String, dynamic> txData;
|
||||||
|
|
||||||
|
@ -519,6 +566,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
|
|
||||||
onCryptoAmountChanged = _cryptoAmountChanged;
|
onCryptoAmountChanged = _cryptoAmountChanged;
|
||||||
cryptoAmountController.addListener(onCryptoAmountChanged);
|
cryptoAmountController.addListener(onCryptoAmountChanged);
|
||||||
|
baseAmountController.addListener(_baseAmountChanged);
|
||||||
|
|
||||||
if (_data != null) {
|
if (_data != null) {
|
||||||
if (_data!.amount != null) {
|
if (_data!.amount != null) {
|
||||||
|
@ -534,43 +582,47 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
noteController.text = "PayNym send";
|
noteController.text = "PayNym send";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coin != Coin.epicCash) {
|
// if (coin != Coin.epicCash) {
|
||||||
_cryptoFocus.addListener(() {
|
// _cryptoFocus.addListener(() {
|
||||||
if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
// if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
||||||
if (_amountToSend == null) {
|
// if (_amountToSend == null) {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_calculateFeesFuture = calculateFees(0);
|
// _calculateFeesFuture = calculateFees(0);
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_calculateFeesFuture = calculateFees(
|
// _calculateFeesFuture = calculateFees(
|
||||||
Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
// Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
_baseFocus.addListener(() {
|
// _baseFocus.addListener(() {
|
||||||
if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
// if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
||||||
if (_amountToSend == null) {
|
// if (_amountToSend == null) {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_calculateFeesFuture = calculateFees(0);
|
// _calculateFeesFuture = calculateFees(0);
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_calculateFeesFuture = calculateFees(
|
// _calculateFeesFuture = calculateFees(
|
||||||
Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
// Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_cryptoAmountChangedFeeUpdateTimer?.cancel();
|
||||||
|
_baseAmountChangedFeeUpdateTimer?.cancel();
|
||||||
|
|
||||||
cryptoAmountController.removeListener(onCryptoAmountChanged);
|
cryptoAmountController.removeListener(onCryptoAmountChanged);
|
||||||
|
baseAmountController.removeListener(_baseAmountChanged);
|
||||||
|
|
||||||
sendToController.dispose();
|
sendToController.dispose();
|
||||||
cryptoAmountController.dispose();
|
cryptoAmountController.dispose();
|
||||||
|
@ -1569,26 +1621,52 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
? "Select coins"
|
? "Select coins"
|
||||||
: "Selected coins (${selectedUTXOs.length})",
|
: "Selected coins (${selectedUTXOs.length})",
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final result =
|
if (FocusScope.of(context).hasFocus) {
|
||||||
await Navigator.of(context).pushNamed(
|
FocusScope.of(context).unfocus();
|
||||||
CoinControlView.routeName,
|
await Future<void>.delayed(
|
||||||
arguments: Tuple4(
|
const Duration(milliseconds: 100),
|
||||||
walletId,
|
);
|
||||||
CoinControlViewType.use,
|
}
|
||||||
_amountToSend != null
|
|
||||||
? Format.decimalAmountToSatoshis(
|
|
||||||
_amountToSend!,
|
|
||||||
coin,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
selectedUTXOs,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result is Set<UTXO>) {
|
if (mounted) {
|
||||||
setState(() {
|
final spendable = ref
|
||||||
selectedUTXOs = result;
|
.read(walletsChangeNotifierProvider)
|
||||||
});
|
.getManager(widget.walletId)
|
||||||
|
.balance
|
||||||
|
.spendable;
|
||||||
|
|
||||||
|
int? amount;
|
||||||
|
if (_amountToSend != null) {
|
||||||
|
amount =
|
||||||
|
Format.decimalAmountToSatoshis(
|
||||||
|
_amountToSend!,
|
||||||
|
coin,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (spendable == amount) {
|
||||||
|
// this is now a send all
|
||||||
|
} else {
|
||||||
|
amount += _currentFee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await Navigator.of(context)
|
||||||
|
.pushNamed(
|
||||||
|
CoinControlView.routeName,
|
||||||
|
arguments: Tuple4(
|
||||||
|
walletId,
|
||||||
|
CoinControlViewType.use,
|
||||||
|
amount,
|
||||||
|
selectedUTXOs,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result is Set<UTXO>) {
|
||||||
|
setState(() {
|
||||||
|
selectedUTXOs = result;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -1711,6 +1789,10 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
.text) ??
|
.text) ??
|
||||||
Decimal.zero,
|
Decimal.zero,
|
||||||
updateChosen: (String fee) {
|
updateChosen: (String fee) {
|
||||||
|
_setCurrentFee(
|
||||||
|
fee,
|
||||||
|
true,
|
||||||
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
_calculateFeesFuture =
|
_calculateFeesFuture =
|
||||||
Future(() => fee);
|
Future(() => fee);
|
||||||
|
@ -1736,6 +1818,10 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
ConnectionState
|
ConnectionState
|
||||||
.done &&
|
.done &&
|
||||||
snapshot.hasData) {
|
snapshot.hasData) {
|
||||||
|
_setCurrentFee(
|
||||||
|
snapshot.data! as String,
|
||||||
|
false,
|
||||||
|
);
|
||||||
return Text(
|
return Text(
|
||||||
"~${snapshot.data! as String} ${coin.ticker}",
|
"~${snapshot.data! as String} ${coin.ticker}",
|
||||||
style: STextStyles
|
style: STextStyles
|
||||||
|
@ -1788,6 +1874,11 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
ConnectionState
|
ConnectionState
|
||||||
.done &&
|
.done &&
|
||||||
snapshot.hasData) {
|
snapshot.hasData) {
|
||||||
|
_setCurrentFee(
|
||||||
|
snapshot.data!
|
||||||
|
as String,
|
||||||
|
false,
|
||||||
|
);
|
||||||
return Text(
|
return Text(
|
||||||
"~${snapshot.data! as String} ${coin.ticker}",
|
"~${snapshot.data! as String} ${coin.ticker}",
|
||||||
style: STextStyles
|
style: STextStyles
|
||||||
|
|
|
@ -18,6 +18,7 @@ import 'package:stackwallet/exceptions/electrumx/no_such_transaction.dart';
|
||||||
import 'package:stackwallet/models/balance.dart';
|
import 'package:stackwallet/models/balance.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -1151,13 +1152,15 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool coinControl = utxos != null;
|
||||||
|
|
||||||
final txData = await coinSelection(
|
final txData = await coinSelection(
|
||||||
satoshiAmountToSend: satoshiAmount,
|
satoshiAmountToSend: satoshiAmount,
|
||||||
selectedTxFeeRate: rate,
|
selectedTxFeeRate: rate,
|
||||||
recipientAddress: address,
|
recipientAddress: address,
|
||||||
isSendAll: isSendAll,
|
isSendAll: isSendAll,
|
||||||
utxos: utxos?.toList(),
|
utxos: utxos?.toList(),
|
||||||
coinControl: utxos is List<isar_models.UTXO>,
|
coinControl: coinControl,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||||
|
@ -1841,14 +1844,16 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
String? blockReason;
|
String? blockReason;
|
||||||
|
|
||||||
if (storedTx?.subType ==
|
if (storedTx?.subType ==
|
||||||
isar_models.TransactionSubType.bip47Notification &&
|
isar_models.TransactionSubType.bip47Notification) {
|
||||||
storedTx?.type == isar_models.TransactionType.incoming) {
|
if (storedTx?.type == isar_models.TransactionType.incoming) {
|
||||||
// probably safe to assume this is an incoming tx as it is a utxo
|
shouldBlock = true;
|
||||||
// belonging to this wallet. The extra check may be redundant but
|
blockReason = "Incoming paynym notification transaction.";
|
||||||
// just in case...
|
} else if (storedTx?.type == isar_models.TransactionType.outgoing) {
|
||||||
|
shouldBlock = true;
|
||||||
shouldBlock = true;
|
blockReason = "Paynym notification change output. Incautious "
|
||||||
blockReason = "Incoming paynym notification transaction.";
|
"handling of change outputs from notification transactions "
|
||||||
|
"may cause unintended loss of privacy.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final vout = jsonUTXO["tx_pos"] as int;
|
final vout = jsonUTXO["tx_pos"] as int;
|
||||||
|
@ -2360,6 +2365,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
} else {
|
} else {
|
||||||
satoshisBeingUsed = spendableSatoshiValue;
|
satoshisBeingUsed = spendableSatoshiValue;
|
||||||
utxoObjectsToUse = spendableOutputs;
|
utxoObjectsToUse = spendableOutputs;
|
||||||
|
inputsBeingConsumed = spendableOutputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2381,7 +2387,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -2399,7 +2404,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: [amount],
|
satoshiAmounts: [amount],
|
||||||
|
@ -2410,7 +2414,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": amount,
|
"recipientAmt": amount,
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2418,7 +2422,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
final int vSizeForOneOutput;
|
final int vSizeForOneOutput;
|
||||||
try {
|
try {
|
||||||
vSizeForOneOutput = (await buildTransaction(
|
vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -2431,7 +2434,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
final int vSizeForTwoOutPuts;
|
final int vSizeForTwoOutPuts;
|
||||||
try {
|
try {
|
||||||
vSizeForTwoOutPuts = (await buildTransaction(
|
vSizeForTwoOutPuts = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [
|
recipients: [
|
||||||
recipientAddress,
|
recipientAddress,
|
||||||
|
@ -2502,7 +2504,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2530,7 +2531,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2543,7 +2543,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2560,7 +2560,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2571,7 +2570,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2590,7 +2589,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2601,7 +2599,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2620,7 +2618,6 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2631,7 +2628,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2657,241 +2654,144 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
Future<List<SigningData>> fetchBuildTxData(
|
||||||
List<isar_models.UTXO> utxosToUse,
|
List<isar_models.UTXO> utxosToUse,
|
||||||
) async {
|
) async {
|
||||||
// return data
|
// return data
|
||||||
Map<String, dynamic> results = {};
|
List<SigningData> signingData = [];
|
||||||
Map<String, List<String>> addressTxid = {};
|
|
||||||
|
|
||||||
// addresses to check
|
|
||||||
List<String> addressesP2PKH = [];
|
|
||||||
List<String> addressesP2SH = [];
|
|
||||||
List<String> addressesP2WPKH = [];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Populating the addresses to check
|
// Populating the addresses to check
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
if (utxosToUse[i].address == null) {
|
||||||
final tx = await _cachedElectrumXClient.getTransaction(
|
final txid = utxosToUse[i].txid;
|
||||||
txHash: txid,
|
final tx = await _cachedElectrumXClient.getTransaction(
|
||||||
coin: coin,
|
txHash: txid,
|
||||||
);
|
coin: coin,
|
||||||
|
);
|
||||||
for (final output in tx["vout"] as List) {
|
for (final output in tx["vout"] as List) {
|
||||||
final n = output["n"];
|
final n = output["n"];
|
||||||
if (n != null && n == utxosToUse[i].vout) {
|
if (n != null && n == utxosToUse[i].vout) {
|
||||||
final address = output["scriptPubKey"]["address"] as String;
|
utxosToUse[i] = utxosToUse[i].copyWith(
|
||||||
if (!addressTxid.containsKey(address)) {
|
address: output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
addressTxid[address] = <String>[];
|
output["scriptPubKey"]["address"] as String,
|
||||||
}
|
);
|
||||||
(addressTxid[address] as List).add(txid);
|
|
||||||
switch (addressType(address: address)) {
|
|
||||||
case DerivePathType.bip44:
|
|
||||||
addressesP2PKH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip49:
|
|
||||||
addressesP2SH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip84:
|
|
||||||
addressesP2WPKH.add(address);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception("DerivePathType unsupported");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||||
|
|
||||||
|
signingData.add(
|
||||||
|
SigningData(
|
||||||
|
derivePathType: derivePathType,
|
||||||
|
utxo: utxosToUse[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// p2pkh / bip44
|
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||||
final p2pkhLength = addressesP2PKH.length;
|
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||||
if (p2pkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2pkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2PKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
for (final sd in signingData) {
|
||||||
results[tx] = {
|
String? pubKey;
|
||||||
"output": data.output,
|
String? wif;
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
// fetch receiving derivations if null
|
||||||
network: _network,
|
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
),
|
chain: 0,
|
||||||
};
|
derivePathType: sd.derivePathType,
|
||||||
}
|
);
|
||||||
} else {
|
final receiveDerivation =
|
||||||
// if its not a receive, check change
|
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
final changeDerivation = changeDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
if (receiveDerivation != null) {
|
||||||
if (changeDerivation != null) {
|
pubKey = receiveDerivation["pubKey"] as String;
|
||||||
final data = P2PKH(
|
wif = receiveDerivation["wif"] as String;
|
||||||
|
} else {
|
||||||
|
// fetch change derivations if null
|
||||||
|
changeDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
|
chain: 1,
|
||||||
|
derivePathType: sd.derivePathType,
|
||||||
|
);
|
||||||
|
final changeDerivation =
|
||||||
|
changeDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
|
if (changeDerivation != null) {
|
||||||
|
pubKey = changeDerivation["pubKey"] as String;
|
||||||
|
wif = changeDerivation["wif"] as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif == null || pubKey == null) {
|
||||||
|
final address = await db.getAddress(walletId, sd.utxo.address!);
|
||||||
|
if (address?.derivationPath != null) {
|
||||||
|
final node = await Bip32Utils.getBip32Node(
|
||||||
|
(await mnemonicString)!,
|
||||||
|
(await mnemonicPassphrase)!,
|
||||||
|
_network,
|
||||||
|
address!.derivationPath!.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
wif = node.toWIF();
|
||||||
|
pubKey = Format.uint8listToString(node.publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif != null && pubKey != null) {
|
||||||
|
final PaymentData data;
|
||||||
|
final Uint8List? redeemScript;
|
||||||
|
|
||||||
|
switch (sd.derivePathType) {
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
data = P2PKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
case DerivePathType.bip49:
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2sh / bip49
|
|
||||||
final p2shLength = addressesP2SH.length;
|
|
||||||
if (p2shLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip49,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip49,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2shLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2SH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final p2wpkh = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
final redeemScript = p2wpkh.output;
|
|
||||||
|
|
||||||
final data =
|
|
||||||
P2SH(data: PaymentData(redeem: p2wpkh), network: _network).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2SH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
"redeemScript": redeemScript,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if its not a receive, check change
|
|
||||||
final changeDerivation = changeDerivations[addressesP2SH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (changeDerivation != null) {
|
|
||||||
final p2wpkh = P2WPKH(
|
final p2wpkh = P2WPKH(
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
changeDerivation["pubKey"] as String)),
|
|
||||||
network: _network)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
final redeemScript = p2wpkh.output;
|
|
||||||
|
|
||||||
final data =
|
|
||||||
P2SH(data: PaymentData(redeem: p2wpkh), network: _network)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2SH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
"redeemScript": redeemScript,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2wpkh / bip84
|
|
||||||
final p2wpkhLength = addressesP2WPKH.length;
|
|
||||||
if (p2wpkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < p2wpkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2WPKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if its not a receive, check change
|
|
||||||
final changeDerivation = changeDerivations[addressesP2WPKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (changeDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = p2wpkh.output;
|
||||||
|
data = P2SH(
|
||||||
|
data: PaymentData(redeem: p2wpkh),
|
||||||
|
network: _network,
|
||||||
|
).data;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
case DerivePathType.bip84:
|
||||||
results[tx] = {
|
data = P2WPKH(
|
||||||
"output": data.output,
|
data: PaymentData(
|
||||||
"keyPair": ECPair.fromWIF(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["wif"] as String,
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
),
|
).data;
|
||||||
};
|
redeemScript = null;
|
||||||
}
|
break;
|
||||||
}
|
|
||||||
|
default:
|
||||||
|
throw Exception("DerivePathType unsupported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final keyPair = ECPair.fromWIF(
|
||||||
|
wif,
|
||||||
|
network: _network,
|
||||||
|
);
|
||||||
|
|
||||||
|
sd.redeemScript = redeemScript;
|
||||||
|
sd.output = data.output;
|
||||||
|
sd.keyPair = keyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return signingData;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
|
@ -2901,8 +2801,7 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
/// Builds and signs a transaction
|
/// Builds and signs a transaction
|
||||||
Future<Map<String, dynamic>> buildTransaction({
|
Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<isar_models.UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -2913,10 +2812,14 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
txb.addInput(
|
||||||
utxoSigningData[txid]["output"] as Uint8List);
|
txid,
|
||||||
|
utxoSigningData[i].utxo.vout,
|
||||||
|
null,
|
||||||
|
utxoSigningData[i].output!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add transaction output
|
// Add transaction output
|
||||||
|
@ -2926,13 +2829,12 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sign the transaction accordingly
|
// Sign the transaction accordingly
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
|
||||||
txb.sign(
|
txb.sign(
|
||||||
vin: i,
|
vin: i,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
keyPair: utxoSigningData[i].keyPair!,
|
||||||
witnessValue: utxosToUse[i].value,
|
witnessValue: utxoSigningData[i].utxo.value,
|
||||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
redeemScript: utxoSigningData[i].redeemScript,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|
|
@ -1081,13 +1081,15 @@ class BitcoinCashWallet extends CoinServiceAPI
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool coinControl = utxos != null;
|
||||||
|
|
||||||
final result = await coinSelection(
|
final result = await coinSelection(
|
||||||
satoshiAmountToSend: satoshiAmount,
|
satoshiAmountToSend: satoshiAmount,
|
||||||
selectedTxFeeRate: rate,
|
selectedTxFeeRate: rate,
|
||||||
recipientAddress: address,
|
recipientAddress: address,
|
||||||
isSendAll: isSendAll,
|
isSendAll: isSendAll,
|
||||||
utxos: utxos?.toList(),
|
utxos: utxos?.toList(),
|
||||||
coinControl: utxos is List<isar_models.UTXO>,
|
coinControl: coinControl,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2426,6 +2428,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
||||||
} else {
|
} else {
|
||||||
satoshisBeingUsed = spendableSatoshiValue;
|
satoshisBeingUsed = spendableSatoshiValue;
|
||||||
utxoObjectsToUse = spendableOutputs;
|
utxoObjectsToUse = spendableOutputs;
|
||||||
|
inputsBeingConsumed = spendableOutputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
|
|
@ -1,815 +0,0 @@
|
||||||
// import 'dart:convert';
|
|
||||||
// import 'dart:typed_data';
|
|
||||||
//
|
|
||||||
// import 'package:bip32/bip32.dart' as bip32;
|
|
||||||
// import 'package:bip47/bip47.dart';
|
|
||||||
// import 'package:bip47/src/util.dart';
|
|
||||||
// import 'package:bitcoindart/bitcoindart.dart' as btc_dart;
|
|
||||||
// import 'package:bitcoindart/src/utils/constants/op.dart' as op;
|
|
||||||
// import 'package:bitcoindart/src/utils/script.dart' as bscript;
|
|
||||||
// import 'package:isar/isar.dart';
|
|
||||||
// import 'package:pointycastle/digests/sha256.dart';
|
|
||||||
// import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dart';
|
|
||||||
// import 'package:stackwallet/exceptions/wallet/paynym_send_exception.dart';
|
|
||||||
// import 'package:stackwallet/models/isar/models/isar_models.dart';
|
|
||||||
// import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
|
||||||
// import 'package:stackwallet/utilities/bip32_utils.dart';
|
|
||||||
// import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
|
||||||
// import 'package:stackwallet/utilities/format.dart';
|
|
||||||
// import 'package:stackwallet/utilities/logger.dart';
|
|
||||||
// import 'package:tuple/tuple.dart';
|
|
||||||
//
|
|
||||||
// const kPaynymDerivePath = "m/47'/0'/0'";
|
|
||||||
//
|
|
||||||
// extension PayNym on DogecoinWallet {
|
|
||||||
// // generate bip32 payment code root
|
|
||||||
// Future<bip32.BIP32> getRootNode({
|
|
||||||
// required List<String> mnemonic,
|
|
||||||
// }) async {
|
|
||||||
// final root = await Bip32Utils.getBip32Root(mnemonic.join(" "), network);
|
|
||||||
// return root;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<Uint8List> deriveNotificationPrivateKey({
|
|
||||||
// required List<String> mnemonic,
|
|
||||||
// }) async {
|
|
||||||
// final root = await getRootNode(mnemonic: mnemonic);
|
|
||||||
// final node = root.derivePath(kPaynymDerivePath).derive(0);
|
|
||||||
// return node.privateKey!;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// fetch or generate this wallet's bip47 payment code
|
|
||||||
// Future<PaymentCode> getPaymentCode(
|
|
||||||
// DerivePathType derivePathType,
|
|
||||||
// ) async {
|
|
||||||
// final address = await getMyNotificationAddress(derivePathType);
|
|
||||||
// final paymentCode = PaymentCode.fromPaymentCode(
|
|
||||||
// address.otherData!,
|
|
||||||
// network,
|
|
||||||
// );
|
|
||||||
// return paymentCode;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<Uint8List> signWithNotificationKey(Uint8List data) async {
|
|
||||||
// final privateKey =
|
|
||||||
// await deriveNotificationPrivateKey(mnemonic: await mnemonic);
|
|
||||||
// final pair = btc_dart.ECPair.fromPrivateKey(privateKey, network: network);
|
|
||||||
// final signed = pair.sign(SHA256Digest().process(data));
|
|
||||||
// return signed;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<String> signStringWithNotificationKey(String data) async {
|
|
||||||
// final bytes =
|
|
||||||
// await signWithNotificationKey(Uint8List.fromList(utf8.encode(data)));
|
|
||||||
// return Format.uint8listToString(bytes);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<Future<Map<String, dynamic>>> preparePaymentCodeSend(
|
|
||||||
// {required PaymentCode paymentCode,
|
|
||||||
// required int satoshiAmount,
|
|
||||||
// Map<String, dynamic>? args}) async {
|
|
||||||
// if (!(await hasConnected(paymentCode.notificationAddressP2PKH()))) {
|
|
||||||
// throw PaynymSendException(
|
|
||||||
// "No notification transaction sent to $paymentCode");
|
|
||||||
// } else {
|
|
||||||
// final myPrivateKey =
|
|
||||||
// await deriveNotificationPrivateKey(mnemonic: await mnemonic);
|
|
||||||
// final sendToAddress = await nextUnusedSendAddressFrom(
|
|
||||||
// pCode: paymentCode,
|
|
||||||
// privateKey: myPrivateKey,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// return prepareSend(
|
|
||||||
// address: sendToAddress.value, satoshiAmount: satoshiAmount);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// get the next unused address to send to given the receiver's payment code
|
|
||||||
// /// and your own private key
|
|
||||||
// Future<Address> nextUnusedSendAddressFrom({
|
|
||||||
// required PaymentCode pCode,
|
|
||||||
// required Uint8List privateKey,
|
|
||||||
// int startIndex = 0,
|
|
||||||
// }) async {
|
|
||||||
// // https://en.bitcoin.it/wiki/BIP_0047#Path_levels
|
|
||||||
// const maxCount = 2147483647;
|
|
||||||
//
|
|
||||||
// for (int i = startIndex; i < maxCount; i++) {
|
|
||||||
// final address = await db
|
|
||||||
// .getAddresses(walletId)
|
|
||||||
// .filter()
|
|
||||||
// .subTypeEqualTo(AddressSubType.paynymSend)
|
|
||||||
// .and()
|
|
||||||
// .otherDataEqualTo(pCode.toString())
|
|
||||||
// .and()
|
|
||||||
// .derivationIndexEqualTo(i)
|
|
||||||
// .findFirst();
|
|
||||||
//
|
|
||||||
// if (address != null) {
|
|
||||||
// final count = await getTxCount(address: address.value);
|
|
||||||
// // return address if unused, otherwise continue to next index
|
|
||||||
// if (count == 0) {
|
|
||||||
// return address;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// final pair = PaymentAddress.initWithPrivateKey(
|
|
||||||
// privateKey,
|
|
||||||
// pCode,
|
|
||||||
// i, // index to use
|
|
||||||
// ).getSendAddressKeyPair();
|
|
||||||
//
|
|
||||||
// // add address to local db
|
|
||||||
// final address = generatePaynymSendAddressFromKeyPair(
|
|
||||||
// pair: pair,
|
|
||||||
// derivationIndex: i,
|
|
||||||
// derivePathType: DerivePathType.bip44,
|
|
||||||
// toPaymentCode: pCode,
|
|
||||||
// );
|
|
||||||
// await db.putAddress(address);
|
|
||||||
//
|
|
||||||
// final count = await getTxCount(address: address.value);
|
|
||||||
// // return address if unused, otherwise continue to next index
|
|
||||||
// if (count == 0) {
|
|
||||||
// return address;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// throw PaynymSendException("Exhausted unused send addresses!");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<Map<String, dynamic>> prepareNotificationTx({
|
|
||||||
// required int selectedTxFeeRate,
|
|
||||||
// required String targetPaymentCodeString,
|
|
||||||
// int additionalOutputs = 0,
|
|
||||||
// List<UTXO>? utxos,
|
|
||||||
// }) async {
|
|
||||||
// const amountToSend = DUST_LIMIT;
|
|
||||||
// final List<UTXO> availableOutputs = utxos ?? await this.utxos;
|
|
||||||
// final List<UTXO> spendableOutputs = [];
|
|
||||||
// int spendableSatoshiValue = 0;
|
|
||||||
//
|
|
||||||
// // Build list of spendable outputs and totaling their satoshi amount
|
|
||||||
// for (var i = 0; i < availableOutputs.length; i++) {
|
|
||||||
// if (availableOutputs[i].isBlocked == false &&
|
|
||||||
// availableOutputs[i]
|
|
||||||
// .isConfirmed(await chainHeight, MINIMUM_CONFIRMATIONS) ==
|
|
||||||
// true) {
|
|
||||||
// spendableOutputs.add(availableOutputs[i]);
|
|
||||||
// spendableSatoshiValue += availableOutputs[i].value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (spendableSatoshiValue < amountToSend) {
|
|
||||||
// // insufficient balance
|
|
||||||
// throw InsufficientBalanceException(
|
|
||||||
// "Spendable balance is less than the minimum required for a notification transaction.");
|
|
||||||
// } else if (spendableSatoshiValue == amountToSend) {
|
|
||||||
// // insufficient balance due to missing amount to cover fee
|
|
||||||
// throw InsufficientBalanceException(
|
|
||||||
// "Remaining balance does not cover the network fee.");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // sort spendable by age (oldest first)
|
|
||||||
// spendableOutputs.sort((a, b) => b.blockTime!.compareTo(a.blockTime!));
|
|
||||||
//
|
|
||||||
// int satoshisBeingUsed = 0;
|
|
||||||
// int outputsBeingUsed = 0;
|
|
||||||
// List<UTXO> utxoObjectsToUse = [];
|
|
||||||
//
|
|
||||||
// for (int i = 0;
|
|
||||||
// satoshisBeingUsed < amountToSend && i < spendableOutputs.length;
|
|
||||||
// i++) {
|
|
||||||
// utxoObjectsToUse.add(spendableOutputs[i]);
|
|
||||||
// satoshisBeingUsed += spendableOutputs[i].value;
|
|
||||||
// outputsBeingUsed += 1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // add additional outputs if required
|
|
||||||
// for (int i = 0;
|
|
||||||
// i < additionalOutputs && outputsBeingUsed < spendableOutputs.length;
|
|
||||||
// i++) {
|
|
||||||
// utxoObjectsToUse.add(spendableOutputs[outputsBeingUsed]);
|
|
||||||
// satoshisBeingUsed += spendableOutputs[outputsBeingUsed].value;
|
|
||||||
// outputsBeingUsed += 1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // gather required signing data
|
|
||||||
// final utxoSigningData = await fetchBuildTxData(utxoObjectsToUse);
|
|
||||||
//
|
|
||||||
// final int vSizeForNoChange = (await _createNotificationTx(
|
|
||||||
// targetPaymentCodeString: targetPaymentCodeString,
|
|
||||||
// utxosToUse: utxoObjectsToUse,
|
|
||||||
// utxoSigningData: utxoSigningData,
|
|
||||||
// change: 0))
|
|
||||||
// .item2;
|
|
||||||
//
|
|
||||||
// final int vSizeForWithChange = (await _createNotificationTx(
|
|
||||||
// targetPaymentCodeString: targetPaymentCodeString,
|
|
||||||
// utxosToUse: utxoObjectsToUse,
|
|
||||||
// utxoSigningData: utxoSigningData,
|
|
||||||
// change: satoshisBeingUsed - amountToSend))
|
|
||||||
// .item2;
|
|
||||||
//
|
|
||||||
// // Assume 2 outputs, for recipient and payment code script
|
|
||||||
// int feeForNoChange = estimateTxFee(
|
|
||||||
// vSize: vSizeForNoChange,
|
|
||||||
// feeRatePerKB: selectedTxFeeRate,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // Assume 3 outputs, for recipient, payment code script, and change
|
|
||||||
// int feeForWithChange = estimateTxFee(
|
|
||||||
// vSize: vSizeForWithChange,
|
|
||||||
// feeRatePerKB: selectedTxFeeRate,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// if (feeForNoChange < vSizeForNoChange * 1000) {
|
|
||||||
// feeForNoChange = vSizeForNoChange * 1000;
|
|
||||||
// }
|
|
||||||
// if (feeForWithChange < vSizeForWithChange * 1000) {
|
|
||||||
// feeForWithChange = vSizeForWithChange * 1000;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (satoshisBeingUsed - amountToSend > feeForNoChange + DUST_LIMIT) {
|
|
||||||
// // try to add change output due to "left over" amount being greater than
|
|
||||||
// // the estimated fee + the dust limit
|
|
||||||
// int changeAmount = satoshisBeingUsed - amountToSend - feeForWithChange;
|
|
||||||
//
|
|
||||||
// // check estimates are correct and build notification tx
|
|
||||||
// if (changeAmount >= DUST_LIMIT &&
|
|
||||||
// satoshisBeingUsed - amountToSend - changeAmount == feeForWithChange) {
|
|
||||||
// final txn = await _createNotificationTx(
|
|
||||||
// targetPaymentCodeString: targetPaymentCodeString,
|
|
||||||
// utxosToUse: utxoObjectsToUse,
|
|
||||||
// utxoSigningData: utxoSigningData,
|
|
||||||
// change: changeAmount,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// int feeBeingPaid = satoshisBeingUsed - amountToSend - changeAmount;
|
|
||||||
//
|
|
||||||
// Map<String, dynamic> transactionObject = {
|
|
||||||
// "hex": txn.item1,
|
|
||||||
// "recipientPaynym": targetPaymentCodeString,
|
|
||||||
// "amount": amountToSend,
|
|
||||||
// "fee": feeBeingPaid,
|
|
||||||
// "vSize": txn.item2,
|
|
||||||
// };
|
|
||||||
// return transactionObject;
|
|
||||||
// } else {
|
|
||||||
// // something broke during fee estimation or the change amount is smaller
|
|
||||||
// // than the dust limit. Try without change
|
|
||||||
// final txn = await _createNotificationTx(
|
|
||||||
// targetPaymentCodeString: targetPaymentCodeString,
|
|
||||||
// utxosToUse: utxoObjectsToUse,
|
|
||||||
// utxoSigningData: utxoSigningData,
|
|
||||||
// change: 0,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// int feeBeingPaid = satoshisBeingUsed - amountToSend;
|
|
||||||
//
|
|
||||||
// Map<String, dynamic> transactionObject = {
|
|
||||||
// "hex": txn.item1,
|
|
||||||
// "recipientPaynym": targetPaymentCodeString,
|
|
||||||
// "amount": amountToSend,
|
|
||||||
// "fee": feeBeingPaid,
|
|
||||||
// "vSize": txn.item2,
|
|
||||||
// };
|
|
||||||
// return transactionObject;
|
|
||||||
// }
|
|
||||||
// } else if (satoshisBeingUsed - amountToSend >= feeForNoChange) {
|
|
||||||
// // since we already checked if we need to add a change output we can just
|
|
||||||
// // build without change here
|
|
||||||
// final txn = await _createNotificationTx(
|
|
||||||
// targetPaymentCodeString: targetPaymentCodeString,
|
|
||||||
// utxosToUse: utxoObjectsToUse,
|
|
||||||
// utxoSigningData: utxoSigningData,
|
|
||||||
// change: 0,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// int feeBeingPaid = satoshisBeingUsed - amountToSend;
|
|
||||||
//
|
|
||||||
// Map<String, dynamic> transactionObject = {
|
|
||||||
// "hex": txn.item1,
|
|
||||||
// "recipientPaynym": targetPaymentCodeString,
|
|
||||||
// "amount": amountToSend,
|
|
||||||
// "fee": feeBeingPaid,
|
|
||||||
// "vSize": txn.item2,
|
|
||||||
// };
|
|
||||||
// return transactionObject;
|
|
||||||
// } else {
|
|
||||||
// // if we get here we do not have enough funds to cover the tx total so we
|
|
||||||
// // check if we have any more available outputs and try again
|
|
||||||
// if (spendableOutputs.length > outputsBeingUsed) {
|
|
||||||
// return prepareNotificationTx(
|
|
||||||
// selectedTxFeeRate: selectedTxFeeRate,
|
|
||||||
// targetPaymentCodeString: targetPaymentCodeString,
|
|
||||||
// additionalOutputs: additionalOutputs + 1,
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// throw InsufficientBalanceException(
|
|
||||||
// "Remaining balance does not cover the network fee.");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // return tuple with string value equal to the raw tx hex and the int value
|
|
||||||
// // equal to its vSize
|
|
||||||
// Future<Tuple2<String, int>> _createNotificationTx({
|
|
||||||
// required String targetPaymentCodeString,
|
|
||||||
// required List<UTXO> utxosToUse,
|
|
||||||
// required Map<String, dynamic> utxoSigningData,
|
|
||||||
// required int change,
|
|
||||||
// }) async {
|
|
||||||
// final targetPaymentCode =
|
|
||||||
// PaymentCode.fromPaymentCode(targetPaymentCodeString, network);
|
|
||||||
// final myCode = await getPaymentCode(DerivePathType.bip44);
|
|
||||||
//
|
|
||||||
// final utxo = utxosToUse.first;
|
|
||||||
// final txPoint = utxo.txid.fromHex.toList();
|
|
||||||
// final txPointIndex = utxo.vout;
|
|
||||||
//
|
|
||||||
// final rev = Uint8List(txPoint.length + 4);
|
|
||||||
// Util.copyBytes(Uint8List.fromList(txPoint), 0, rev, 0, txPoint.length);
|
|
||||||
// final buffer = rev.buffer.asByteData();
|
|
||||||
// buffer.setUint32(txPoint.length, txPointIndex, Endian.little);
|
|
||||||
//
|
|
||||||
// final myKeyPair = utxoSigningData[utxo.txid]["keyPair"] as btc_dart.ECPair;
|
|
||||||
//
|
|
||||||
// final S = SecretPoint(
|
|
||||||
// myKeyPair.privateKey!,
|
|
||||||
// targetPaymentCode.notificationPublicKey(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// final blindingMask = PaymentCode.getMask(S.ecdhSecret(), rev);
|
|
||||||
//
|
|
||||||
// final blindedPaymentCode = PaymentCode.blind(
|
|
||||||
// myCode.getPayload(),
|
|
||||||
// blindingMask,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// final opReturnScript = bscript.compile([
|
|
||||||
// (op.OPS["OP_RETURN"] as int),
|
|
||||||
// blindedPaymentCode,
|
|
||||||
// ]);
|
|
||||||
//
|
|
||||||
// // build a notification tx
|
|
||||||
// final txb = btc_dart.TransactionBuilder(network: network);
|
|
||||||
// txb.setVersion(1);
|
|
||||||
//
|
|
||||||
// txb.addInput(
|
|
||||||
// utxo.txid,
|
|
||||||
// txPointIndex,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // todo: modify address once segwit support is in our bip47
|
|
||||||
// txb.addOutput(targetPaymentCode.notificationAddressP2PKH(), DUST_LIMIT);
|
|
||||||
// txb.addOutput(opReturnScript, 0);
|
|
||||||
//
|
|
||||||
// // TODO: add possible change output and mark output as dangerous
|
|
||||||
// if (change > 0) {
|
|
||||||
// // generate new change address if current change address has been used
|
|
||||||
// await checkChangeAddressForTransactions();
|
|
||||||
// final String changeAddress = await currentChangeAddress;
|
|
||||||
// txb.addOutput(changeAddress, change);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// txb.sign(
|
|
||||||
// vin: 0,
|
|
||||||
// keyPair: myKeyPair,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// // sign rest of possible inputs
|
|
||||||
// for (var i = 1; i < utxosToUse.length - 1; i++) {
|
|
||||||
// final txid = utxosToUse[i].txid;
|
|
||||||
// txb.sign(
|
|
||||||
// vin: i,
|
|
||||||
// keyPair: utxoSigningData[txid]["keyPair"] as btc_dart.ECPair,
|
|
||||||
// // witnessValue: utxosToUse[i].value,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final builtTx = txb.build();
|
|
||||||
//
|
|
||||||
// return Tuple2(builtTx.toHex(), builtTx.virtualSize());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<String> broadcastNotificationTx(
|
|
||||||
// {required Map<String, dynamic> preparedTx}) async {
|
|
||||||
// try {
|
|
||||||
// Logging.instance.log("confirmNotificationTx txData: $preparedTx",
|
|
||||||
// level: LogLevel.Info);
|
|
||||||
// final txHash = await electrumXClient.broadcastTransaction(
|
|
||||||
// rawTx: preparedTx["hex"] as String);
|
|
||||||
// Logging.instance.log("Sent txHash: $txHash", level: LogLevel.Info);
|
|
||||||
//
|
|
||||||
// // TODO: only refresh transaction data
|
|
||||||
// try {
|
|
||||||
// await refresh();
|
|
||||||
// } catch (e) {
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "refresh() failed in confirmNotificationTx ($walletName::$walletId): $e",
|
|
||||||
// level: LogLevel.Error,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return txHash;
|
|
||||||
// } catch (e, s) {
|
|
||||||
// Logging.instance.log("Exception rethrown from confirmSend(): $e\n$s",
|
|
||||||
// level: LogLevel.Error);
|
|
||||||
// rethrow;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // TODO optimize
|
|
||||||
// Future<bool> hasConnected(String paymentCodeString) async {
|
|
||||||
// final myNotificationAddress =
|
|
||||||
// await getMyNotificationAddress(DerivePathTypeExt.primaryFor(coin));
|
|
||||||
//
|
|
||||||
// final txns = await db
|
|
||||||
// .getTransactions(walletId)
|
|
||||||
// .filter()
|
|
||||||
// .subTypeEqualTo(TransactionSubType.bip47Notification)
|
|
||||||
// .findAll();
|
|
||||||
//
|
|
||||||
// for (final tx in txns) {
|
|
||||||
// // quick check that may cause problems?
|
|
||||||
// if (tx.address.value?.value == myNotificationAddress.value) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final unBlindedPaymentCode = await unBlindedPaymentCodeFromTransaction(
|
|
||||||
// transaction: tx,
|
|
||||||
// myNotificationAddress: myNotificationAddress,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// if (paymentCodeString == unBlindedPaymentCode.toString()) {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // otherwise return no
|
|
||||||
// return false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<PaymentCode?> unBlindedPaymentCodeFromTransaction({
|
|
||||||
// required Transaction transaction,
|
|
||||||
// required Address myNotificationAddress,
|
|
||||||
// }) async {
|
|
||||||
// if (transaction.address.value != null &&
|
|
||||||
// transaction.address.value!.value != myNotificationAddress.value) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// final blindedCode =
|
|
||||||
// transaction.outputs.elementAt(1).scriptPubKeyAsm!.split(" ")[1];
|
|
||||||
//
|
|
||||||
// final designatedInput = transaction.inputs.first;
|
|
||||||
//
|
|
||||||
// final txPoint = designatedInput.txid.fromHex.toList();
|
|
||||||
// final txPointIndex = designatedInput.vout;
|
|
||||||
//
|
|
||||||
// final rev = Uint8List(txPoint.length + 4);
|
|
||||||
// Util.copyBytes(Uint8List.fromList(txPoint), 0, rev, 0, txPoint.length);
|
|
||||||
// final buffer = rev.buffer.asByteData();
|
|
||||||
// buffer.setUint32(txPoint.length, txPointIndex, Endian.little);
|
|
||||||
//
|
|
||||||
// final pubKey = designatedInput.scriptSigAsm!.split(" ")[1].fromHex;
|
|
||||||
//
|
|
||||||
// final myPrivateKey =
|
|
||||||
// await deriveNotificationPrivateKey(mnemonic: await mnemonic);
|
|
||||||
//
|
|
||||||
// final S = SecretPoint(myPrivateKey, pubKey);
|
|
||||||
//
|
|
||||||
// final mask = PaymentCode.getMask(S.ecdhSecret(), rev);
|
|
||||||
//
|
|
||||||
// final unBlindedPayload = PaymentCode.blind(blindedCode.fromHex, mask);
|
|
||||||
//
|
|
||||||
// final unBlindedPaymentCode =
|
|
||||||
// PaymentCode.initFromPayload(unBlindedPayload);
|
|
||||||
//
|
|
||||||
// return unBlindedPaymentCode;
|
|
||||||
// } catch (e) {
|
|
||||||
// Logging.instance.log(
|
|
||||||
// "unBlindedPaymentCodeFromTransaction() failed: $e",
|
|
||||||
// level: LogLevel.Warning,
|
|
||||||
// );
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<List<PaymentCode>>
|
|
||||||
// getAllPaymentCodesFromNotificationTransactions() async {
|
|
||||||
// final myAddress =
|
|
||||||
// await getMyNotificationAddress(DerivePathTypeExt.primaryFor(coin));
|
|
||||||
// final txns = await db
|
|
||||||
// .getTransactions(walletId)
|
|
||||||
// .filter()
|
|
||||||
// .subTypeEqualTo(TransactionSubType.bip47Notification)
|
|
||||||
// .findAll();
|
|
||||||
//
|
|
||||||
// List<PaymentCode> unBlindedList = [];
|
|
||||||
//
|
|
||||||
// for (final tx in txns) {
|
|
||||||
// final unBlinded = await unBlindedPaymentCodeFromTransaction(
|
|
||||||
// transaction: tx,
|
|
||||||
// myNotificationAddress: myAddress,
|
|
||||||
// );
|
|
||||||
// if (unBlinded != null) {
|
|
||||||
// unBlindedList.add(unBlinded);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return unBlindedList;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<void> restoreHistoryWith(
|
|
||||||
// PaymentCode other,
|
|
||||||
// int maxUnusedAddressGap,
|
|
||||||
// int maxNumberOfIndexesToCheck,
|
|
||||||
// ) async {
|
|
||||||
// // https://en.bitcoin.it/wiki/BIP_0047#Path_levels
|
|
||||||
// const maxCount = 2147483647;
|
|
||||||
// assert(maxNumberOfIndexesToCheck < maxCount);
|
|
||||||
//
|
|
||||||
// final myPrivateKey =
|
|
||||||
// await deriveNotificationPrivateKey(mnemonic: await mnemonic);
|
|
||||||
//
|
|
||||||
// List<Address> addresses = [];
|
|
||||||
// int receivingGapCounter = 0;
|
|
||||||
// int outgoingGapCounter = 0;
|
|
||||||
//
|
|
||||||
// for (int i = 0;
|
|
||||||
// i < maxNumberOfIndexesToCheck &&
|
|
||||||
// (receivingGapCounter < maxUnusedAddressGap ||
|
|
||||||
// outgoingGapCounter < maxUnusedAddressGap);
|
|
||||||
// i++) {
|
|
||||||
// final paymentAddress = PaymentAddress.initWithPrivateKey(
|
|
||||||
// myPrivateKey,
|
|
||||||
// other,
|
|
||||||
// i, // index to use
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// if (receivingGapCounter < maxUnusedAddressGap) {
|
|
||||||
// final pair = paymentAddress.getSendAddressKeyPair();
|
|
||||||
// final address = generatePaynymSendAddressFromKeyPair(
|
|
||||||
// pair: pair,
|
|
||||||
// derivationIndex: i,
|
|
||||||
// derivePathType: DerivePathType.bip44,
|
|
||||||
// toPaymentCode: other,
|
|
||||||
// );
|
|
||||||
// addresses.add(address);
|
|
||||||
//
|
|
||||||
// final count = await getTxCount(address: address.value);
|
|
||||||
//
|
|
||||||
// if (count > 0) {
|
|
||||||
// receivingGapCounter++;
|
|
||||||
// } else {
|
|
||||||
// receivingGapCounter = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (outgoingGapCounter < maxUnusedAddressGap) {
|
|
||||||
// final pair = paymentAddress.getReceiveAddressKeyPair();
|
|
||||||
// final address = generatePaynymReceivingAddressFromKeyPair(
|
|
||||||
// pair: pair,
|
|
||||||
// derivationIndex: i,
|
|
||||||
// derivePathType: DerivePathType.bip44,
|
|
||||||
// fromPaymentCode: other,
|
|
||||||
// );
|
|
||||||
// addresses.add(address);
|
|
||||||
//
|
|
||||||
// final count = await getTxCount(address: address.value);
|
|
||||||
//
|
|
||||||
// if (count > 0) {
|
|
||||||
// outgoingGapCounter++;
|
|
||||||
// } else {
|
|
||||||
// outgoingGapCounter = 0;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// await db.putAddresses(addresses);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Address generatePaynymSendAddressFromKeyPair({
|
|
||||||
// required btc_dart.ECPair pair,
|
|
||||||
// required int derivationIndex,
|
|
||||||
// required DerivePathType derivePathType,
|
|
||||||
// required PaymentCode toPaymentCode,
|
|
||||||
// }) {
|
|
||||||
// final data = btc_dart.PaymentData(pubkey: pair.publicKey);
|
|
||||||
//
|
|
||||||
// String addressString;
|
|
||||||
// switch (derivePathType) {
|
|
||||||
// case DerivePathType.bip44:
|
|
||||||
// addressString =
|
|
||||||
// btc_dart.P2PKH(data: data, network: network).data.address!;
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// // The following doesn't apply currently
|
|
||||||
// // case DerivePathType.bip49:
|
|
||||||
// // addressString = btc_dart
|
|
||||||
// // .P2SH(
|
|
||||||
// // data: btc_dart.PaymentData(
|
|
||||||
// // redeem: btc_dart
|
|
||||||
// // .P2WPKH(
|
|
||||||
// // data: data,
|
|
||||||
// // network: network,
|
|
||||||
// // )
|
|
||||||
// // .data),
|
|
||||||
// // network: network,
|
|
||||||
// // )
|
|
||||||
// // .data
|
|
||||||
// // .address!;
|
|
||||||
// // break;
|
|
||||||
// //
|
|
||||||
// // case DerivePathType.bip84:
|
|
||||||
// // addressString = btc_dart
|
|
||||||
// // .P2WPKH(
|
|
||||||
// // network: network,
|
|
||||||
// // data: data,
|
|
||||||
// // )
|
|
||||||
// // .data
|
|
||||||
// // .address!;
|
|
||||||
// // break;
|
|
||||||
// default:
|
|
||||||
// throw UnimplementedError("segwit paynyms not implemented yet");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final address = Address(
|
|
||||||
// walletId: walletId,
|
|
||||||
// value: addressString,
|
|
||||||
// publicKey: pair.publicKey,
|
|
||||||
// derivationIndex: derivationIndex,
|
|
||||||
// type: AddressType.nonWallet,
|
|
||||||
// subType: AddressSubType.paynymSend,
|
|
||||||
// otherData: toPaymentCode.toString(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// return address;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Address generatePaynymReceivingAddressFromKeyPair({
|
|
||||||
// required btc_dart.ECPair pair,
|
|
||||||
// required int derivationIndex,
|
|
||||||
// required DerivePathType derivePathType,
|
|
||||||
// required PaymentCode fromPaymentCode,
|
|
||||||
// }) {
|
|
||||||
// final data = btc_dart.PaymentData(pubkey: pair.publicKey);
|
|
||||||
//
|
|
||||||
// String addressString;
|
|
||||||
// AddressType addrType;
|
|
||||||
// switch (derivePathType) {
|
|
||||||
// case DerivePathType.bip44:
|
|
||||||
// addressString = btc_dart
|
|
||||||
// .P2PKH(
|
|
||||||
// data: data,
|
|
||||||
// network: network,
|
|
||||||
// )
|
|
||||||
// .data
|
|
||||||
// .address!;
|
|
||||||
// addrType = AddressType.p2pkh;
|
|
||||||
// break;
|
|
||||||
//
|
|
||||||
// // The following doesn't apply currently
|
|
||||||
// // case DerivePathType.bip49:
|
|
||||||
// // addressString = btc_dart
|
|
||||||
// // .P2SH(
|
|
||||||
// // data: btc_dart.PaymentData(
|
|
||||||
// // redeem: btc_dart
|
|
||||||
// // .P2WPKH(
|
|
||||||
// // data: data,
|
|
||||||
// // network: network,
|
|
||||||
// // )
|
|
||||||
// // .data),
|
|
||||||
// // network: network,
|
|
||||||
// // )
|
|
||||||
// // .data
|
|
||||||
// // .address!;
|
|
||||||
// // addrType = AddressType.p2sh;
|
|
||||||
// // break;
|
|
||||||
// //
|
|
||||||
// // case DerivePathType.bip84:
|
|
||||||
// // addressString = btc_dart
|
|
||||||
// // .P2WPKH(
|
|
||||||
// // network: network,
|
|
||||||
// // data: data,
|
|
||||||
// // )
|
|
||||||
// // .data
|
|
||||||
// // .address!;
|
|
||||||
// // addrType = AddressType.p2wpkh;
|
|
||||||
// // break;
|
|
||||||
// default:
|
|
||||||
// throw UnimplementedError("segwit paynyms not implemented yet");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final address = Address(
|
|
||||||
// walletId: walletId,
|
|
||||||
// value: addressString,
|
|
||||||
// publicKey: pair.publicKey,
|
|
||||||
// derivationIndex: derivationIndex,
|
|
||||||
// type: addrType,
|
|
||||||
// subType: AddressSubType.paynymReceive,
|
|
||||||
// otherData: fromPaymentCode.toString(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// return address;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Future<Address> getMyNotificationAddress(
|
|
||||||
// DerivePathType derivePathType,
|
|
||||||
// ) async {
|
|
||||||
// // TODO: fix when segwit is here
|
|
||||||
// derivePathType = DerivePathType.bip44;
|
|
||||||
//
|
|
||||||
// AddressType type;
|
|
||||||
// switch (derivePathType) {
|
|
||||||
// case DerivePathType.bip44:
|
|
||||||
// type = AddressType.p2pkh;
|
|
||||||
// break;
|
|
||||||
// case DerivePathType.bip49:
|
|
||||||
// type = AddressType.p2sh;
|
|
||||||
// break;
|
|
||||||
// case DerivePathType.bip84:
|
|
||||||
// type = AddressType.p2wpkh;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final storedAddress = await db
|
|
||||||
// .getAddresses(walletId)
|
|
||||||
// .filter()
|
|
||||||
// .subTypeEqualTo(AddressSubType.paynymNotification)
|
|
||||||
// .and()
|
|
||||||
// .typeEqualTo(type)
|
|
||||||
// .and()
|
|
||||||
// .not()
|
|
||||||
// .typeEqualTo(AddressType.nonWallet)
|
|
||||||
// .findFirst();
|
|
||||||
//
|
|
||||||
// if (storedAddress != null) {
|
|
||||||
// return storedAddress;
|
|
||||||
// } else {
|
|
||||||
// final root = await getRootNode(mnemonic: await mnemonic);
|
|
||||||
// final node = root.derivePath(kPaynymDerivePath);
|
|
||||||
// final paymentCode = PaymentCode.initFromPubKey(
|
|
||||||
// node.publicKey,
|
|
||||||
// node.chainCode,
|
|
||||||
// network,
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// String addressString;
|
|
||||||
// final data =
|
|
||||||
// btc_dart.PaymentData(pubkey: paymentCode.notificationPublicKey());
|
|
||||||
// switch (derivePathType) {
|
|
||||||
// case DerivePathType.bip44:
|
|
||||||
// addressString = btc_dart
|
|
||||||
// .P2PKH(
|
|
||||||
// data: data,
|
|
||||||
// network: network,
|
|
||||||
// )
|
|
||||||
// .data
|
|
||||||
// .address!;
|
|
||||||
// break;
|
|
||||||
// // case DerivePathType.bip49:
|
|
||||||
// // addressString = btc_dart
|
|
||||||
// // .P2SH(
|
|
||||||
// // data: btc_dart.PaymentData(
|
|
||||||
// // redeem: btc_dart
|
|
||||||
// // .P2WPKH(
|
|
||||||
// // data: data,
|
|
||||||
// // network: network,
|
|
||||||
// // )
|
|
||||||
// // .data),
|
|
||||||
// // network: network,
|
|
||||||
// // )
|
|
||||||
// // .data
|
|
||||||
// // .address!;
|
|
||||||
// // break;
|
|
||||||
// // case DerivePathType.bip84:
|
|
||||||
// // addressString = btc_dart
|
|
||||||
// // .P2WPKH(
|
|
||||||
// // network: network,
|
|
||||||
// // data: data,
|
|
||||||
// // )
|
|
||||||
// // .data
|
|
||||||
// // .address!;
|
|
||||||
// // break;
|
|
||||||
// default:
|
|
||||||
// throw UnimplementedError("segwit paynyms not implemented yet");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final address = Address(
|
|
||||||
// walletId: walletId,
|
|
||||||
// value: addressString,
|
|
||||||
// publicKey: paymentCode.getPubKey(),
|
|
||||||
// derivationIndex: 0,
|
|
||||||
// type: type,
|
|
||||||
// subType: AddressSubType.paynymNotification,
|
|
||||||
// otherData: paymentCode.toString(),
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// await db.putAddress(address);
|
|
||||||
// return address;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -18,6 +18,7 @@ import 'package:stackwallet/exceptions/electrumx/no_such_transaction.dart';
|
||||||
import 'package:stackwallet/models/balance.dart';
|
import 'package:stackwallet/models/balance.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -946,13 +947,15 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool coinControl = utxos != null;
|
||||||
|
|
||||||
final result = await coinSelection(
|
final result = await coinSelection(
|
||||||
satoshiAmountToSend: satoshiAmount,
|
satoshiAmountToSend: satoshiAmount,
|
||||||
selectedTxFeeRate: rate,
|
selectedTxFeeRate: rate,
|
||||||
recipientAddress: address,
|
recipientAddress: address,
|
||||||
isSendAll: isSendAll,
|
isSendAll: isSendAll,
|
||||||
utxos: utxos?.toList(),
|
utxos: utxos?.toList(),
|
||||||
coinControl: utxos is List<isar_models.UTXO>,
|
coinControl: coinControl,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -1586,14 +1589,16 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
String? blockReason;
|
String? blockReason;
|
||||||
|
|
||||||
if (storedTx?.subType ==
|
if (storedTx?.subType ==
|
||||||
isar_models.TransactionSubType.bip47Notification &&
|
isar_models.TransactionSubType.bip47Notification) {
|
||||||
storedTx?.type == isar_models.TransactionType.incoming) {
|
if (storedTx?.type == isar_models.TransactionType.incoming) {
|
||||||
// probably safe to assume this is an incoming tx as it is a utxo
|
shouldBlock = true;
|
||||||
// belonging to this wallet. The extra check may be redundant but
|
blockReason = "Incoming paynym notification transaction.";
|
||||||
// just in case...
|
} else if (storedTx?.type == isar_models.TransactionType.outgoing) {
|
||||||
|
shouldBlock = true;
|
||||||
shouldBlock = true;
|
blockReason = "Paynym notification change output. Incautious "
|
||||||
blockReason = "Incoming paynym notification transaction.";
|
"handling of change outputs from notification transactions "
|
||||||
|
"may cause unintended loss of privacy.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final vout = jsonUTXO["tx_pos"] as int;
|
final vout = jsonUTXO["tx_pos"] as int;
|
||||||
|
@ -2126,6 +2131,7 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
} else {
|
} else {
|
||||||
satoshisBeingUsed = spendableSatoshiValue;
|
satoshisBeingUsed = spendableSatoshiValue;
|
||||||
utxoObjectsToUse = spendableOutputs;
|
utxoObjectsToUse = spendableOutputs;
|
||||||
|
inputsBeingConsumed = spendableOutputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2149,7 +2155,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -2164,7 +2169,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: [amount],
|
satoshiAmounts: [amount],
|
||||||
|
@ -2175,19 +2179,17 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": amount,
|
"recipientAmt": amount,
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
))["vSize"] as int;
|
))["vSize"] as int;
|
||||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [
|
recipients: [
|
||||||
recipientAddress,
|
recipientAddress,
|
||||||
|
@ -2267,7 +2269,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2295,7 +2296,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2308,7 +2308,7 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2325,7 +2325,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2336,7 +2335,7 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2355,7 +2354,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2366,7 +2364,7 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2385,7 +2383,6 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2396,7 +2393,7 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2422,103 +2419,120 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
Future<List<SigningData>> fetchBuildTxData(
|
||||||
List<isar_models.UTXO> utxosToUse,
|
List<isar_models.UTXO> utxosToUse,
|
||||||
) async {
|
) async {
|
||||||
// return data
|
// return data
|
||||||
Map<String, dynamic> results = {};
|
List<SigningData> signingData = [];
|
||||||
Map<String, List<String>> addressTxid = {};
|
|
||||||
|
|
||||||
// addresses to check
|
|
||||||
List<String> addressesP2PKH = [];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Populating the addresses to check
|
// Populating the addresses to check
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
if (utxosToUse[i].address == null) {
|
||||||
final tx = await _cachedElectrumXClient.getTransaction(
|
final txid = utxosToUse[i].txid;
|
||||||
txHash: txid,
|
final tx = await _cachedElectrumXClient.getTransaction(
|
||||||
coin: coin,
|
txHash: txid,
|
||||||
);
|
coin: coin,
|
||||||
|
);
|
||||||
for (final output in tx["vout"] as List) {
|
for (final output in tx["vout"] as List) {
|
||||||
final n = output["n"];
|
final n = output["n"];
|
||||||
if (n != null && n == utxosToUse[i].vout) {
|
if (n != null && n == utxosToUse[i].vout) {
|
||||||
final address = output["scriptPubKey"]["addresses"][0] as String;
|
utxosToUse[i] = utxosToUse[i].copyWith(
|
||||||
if (!addressTxid.containsKey(address)) {
|
address: output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
addressTxid[address] = <String>[];
|
output["scriptPubKey"]["address"] as String,
|
||||||
}
|
);
|
||||||
(addressTxid[address] as List).add(txid);
|
|
||||||
switch (addressType(address: address)) {
|
|
||||||
case DerivePathType.bip44:
|
|
||||||
addressesP2PKH.add(address);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception("Unsupported DerivePathType");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||||
|
|
||||||
|
signingData.add(
|
||||||
|
SigningData(
|
||||||
|
derivePathType: derivePathType,
|
||||||
|
utxo: utxosToUse[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// p2pkh / bip44
|
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||||
final p2pkhLength = addressesP2PKH.length;
|
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||||
if (p2pkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2pkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2PKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
for (final sd in signingData) {
|
||||||
results[tx] = {
|
String? pubKey;
|
||||||
"output": data.output,
|
String? wif;
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
// fetch receiving derivations if null
|
||||||
network: network,
|
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
),
|
chain: 0,
|
||||||
};
|
derivePathType: sd.derivePathType,
|
||||||
}
|
);
|
||||||
} else {
|
final receiveDerivation =
|
||||||
// if its not a receive, check change
|
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
final changeDerivation = changeDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
if (receiveDerivation != null) {
|
||||||
if (changeDerivation != null) {
|
pubKey = receiveDerivation["pubKey"] as String;
|
||||||
final data = P2PKH(
|
wif = receiveDerivation["wif"] as String;
|
||||||
|
} else {
|
||||||
|
// fetch change derivations if null
|
||||||
|
changeDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
|
chain: 1,
|
||||||
|
derivePathType: sd.derivePathType,
|
||||||
|
);
|
||||||
|
final changeDerivation =
|
||||||
|
changeDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
|
if (changeDerivation != null) {
|
||||||
|
pubKey = changeDerivation["pubKey"] as String;
|
||||||
|
wif = changeDerivation["wif"] as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif == null || pubKey == null) {
|
||||||
|
final address = await db.getAddress(walletId, sd.utxo.address!);
|
||||||
|
if (address?.derivationPath != null) {
|
||||||
|
final node = await Bip32Utils.getBip32Node(
|
||||||
|
(await mnemonicString)!,
|
||||||
|
(await mnemonicPassphrase)!,
|
||||||
|
network,
|
||||||
|
address!.derivationPath!.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
wif = node.toWIF();
|
||||||
|
pubKey = Format.uint8listToString(node.publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif != null && pubKey != null) {
|
||||||
|
final PaymentData data;
|
||||||
|
final Uint8List? redeemScript;
|
||||||
|
|
||||||
|
switch (sd.derivePathType) {
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
data = P2PKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: network,
|
network: network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
default:
|
||||||
results[tx] = {
|
throw Exception("DerivePathType unsupported");
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final keyPair = ECPair.fromWIF(
|
||||||
|
wif,
|
||||||
|
network: network,
|
||||||
|
);
|
||||||
|
|
||||||
|
sd.redeemScript = redeemScript;
|
||||||
|
sd.output = data.output;
|
||||||
|
sd.keyPair = keyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return signingData;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
|
@ -2528,8 +2542,7 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
/// Builds and signs a transaction
|
/// Builds and signs a transaction
|
||||||
Future<Map<String, dynamic>> buildTransaction({
|
Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<isar_models.UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -2540,10 +2553,14 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
txb.addInput(
|
||||||
utxoSigningData[txid]["output"] as Uint8List);
|
txid,
|
||||||
|
utxoSigningData[i].utxo.vout,
|
||||||
|
null,
|
||||||
|
utxoSigningData[i].output!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add transaction output
|
// Add transaction output
|
||||||
|
@ -2553,13 +2570,12 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sign the transaction accordingly
|
// Sign the transaction accordingly
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
|
||||||
txb.sign(
|
txb.sign(
|
||||||
vin: i,
|
vin: i,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
keyPair: utxoSigningData[i].keyPair!,
|
||||||
witnessValue: utxosToUse[i].value,
|
witnessValue: utxoSigningData[i].utxo.value,
|
||||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
redeemScript: utxoSigningData[i].redeemScript,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/lelantus_coin.dart';
|
import 'package:stackwallet/models/lelantus_coin.dart';
|
||||||
import 'package:stackwallet/models/lelantus_fee_data.dart';
|
import 'package:stackwallet/models/lelantus_fee_data.dart';
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -36,6 +37,7 @@ import 'package:stackwallet/utilities/bip32_utils.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/default_nodes.dart';
|
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
||||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
|
@ -1367,7 +1369,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [_recipientAddress],
|
recipients: [_recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -1383,7 +1384,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: [amount],
|
satoshiAmounts: [amount],
|
||||||
|
@ -1399,13 +1399,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
}
|
}
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [_recipientAddress],
|
recipients: [_recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
))["vSize"] as int;
|
))["vSize"] as int;
|
||||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [
|
recipients: [
|
||||||
_recipientAddress,
|
_recipientAddress,
|
||||||
|
@ -1484,7 +1482,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -1512,7 +1509,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -1541,7 +1537,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -1570,7 +1565,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -1599,7 +1593,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -1629,119 +1622,141 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
Future<List<SigningData>> fetchBuildTxData(
|
||||||
List<isar_models.UTXO> utxosToUse,
|
List<isar_models.UTXO> utxosToUse,
|
||||||
) async {
|
) async {
|
||||||
// return data
|
// return data
|
||||||
Map<String, dynamic> results = {};
|
List<SigningData> signingData = [];
|
||||||
Map<String, List<String>> addressTxid = {};
|
|
||||||
|
|
||||||
// addresses to check
|
|
||||||
List<String> addresses = [];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Populating the addresses to check
|
// Populating the addresses to check
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
if (utxosToUse[i].address == null) {
|
||||||
final tx = await _cachedElectrumXClient.getTransaction(
|
final txid = utxosToUse[i].txid;
|
||||||
txHash: txid,
|
final tx = await _cachedElectrumXClient.getTransaction(
|
||||||
coin: coin,
|
txHash: txid,
|
||||||
|
coin: coin,
|
||||||
|
);
|
||||||
|
for (final output in tx["vout"] as List) {
|
||||||
|
final n = output["n"];
|
||||||
|
if (n != null && n == utxosToUse[i].vout) {
|
||||||
|
utxosToUse[i] = utxosToUse[i].copyWith(
|
||||||
|
address: output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
|
output["scriptPubKey"]["address"] as String,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signingData.add(
|
||||||
|
SigningData(
|
||||||
|
derivePathType: DerivePathType.bip44,
|
||||||
|
utxo: utxosToUse[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||||
|
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||||
|
|
||||||
|
for (final sd in signingData) {
|
||||||
|
String? pubKey;
|
||||||
|
String? wif;
|
||||||
|
|
||||||
|
// fetch receiving derivations if null
|
||||||
|
receiveDerivations[sd.derivePathType] ??= Map<String, dynamic>.from(
|
||||||
|
jsonDecode((await _secureStore.read(
|
||||||
|
key: "${walletId}_receiveDerivations",
|
||||||
|
)) ??
|
||||||
|
"{}") as Map,
|
||||||
);
|
);
|
||||||
|
|
||||||
for (final output in tx["vout"] as List) {
|
dynamic receiveDerivation;
|
||||||
final n = output["n"];
|
for (int j = 0;
|
||||||
if (n != null && n == utxosToUse[i].vout) {
|
j < receiveDerivations[sd.derivePathType]!.length &&
|
||||||
final address = output["scriptPubKey"]["addresses"][0] as String;
|
receiveDerivation == null;
|
||||||
|
j++) {
|
||||||
if (!addressTxid.containsKey(address)) {
|
if (receiveDerivations[sd.derivePathType]!["$j"]["address"] ==
|
||||||
addressTxid[address] = <String>[];
|
sd.utxo.address!) {
|
||||||
}
|
receiveDerivation = receiveDerivations[sd.derivePathType]!["$j"];
|
||||||
(addressTxid[address] as List).add(txid);
|
|
||||||
|
|
||||||
addresses.add(address);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// p2pkh / bip44
|
if (receiveDerivation != null) {
|
||||||
final addressesLength = addresses.length;
|
pubKey = receiveDerivation["publicKey"] as String;
|
||||||
if (addressesLength > 0) {
|
wif = receiveDerivation["wif"] as String;
|
||||||
final receiveDerivationsString =
|
} else {
|
||||||
await _secureStore.read(key: "${walletId}_receiveDerivations");
|
// fetch change derivations if null
|
||||||
final receiveDerivations = Map<String, dynamic>.from(
|
changeDerivations[sd.derivePathType] ??= Map<String, dynamic>.from(
|
||||||
jsonDecode(receiveDerivationsString ?? "{}") as Map);
|
jsonDecode((await _secureStore.read(
|
||||||
|
key: "${walletId}_changeDerivations",
|
||||||
|
)) ??
|
||||||
|
"{}") as Map,
|
||||||
|
);
|
||||||
|
|
||||||
final changeDerivationsString =
|
dynamic changeDerivation;
|
||||||
await _secureStore.read(key: "${walletId}_changeDerivations");
|
for (int j = 0;
|
||||||
final changeDerivations = Map<String, dynamic>.from(
|
j < changeDerivations[sd.derivePathType]!.length &&
|
||||||
jsonDecode(changeDerivationsString ?? "{}") as Map);
|
changeDerivation == null;
|
||||||
|
j++) {
|
||||||
for (int i = 0; i < addressesLength; i++) {
|
if (changeDerivations[sd.derivePathType]!["$j"]["address"] ==
|
||||||
// receives
|
sd.utxo.address!) {
|
||||||
|
changeDerivation = changeDerivations[sd.derivePathType]!["$j"];
|
||||||
dynamic receiveDerivation;
|
|
||||||
|
|
||||||
for (int j = 0; j < receiveDerivations.length; j++) {
|
|
||||||
if (receiveDerivations["$j"]["address"] == addresses[i]) {
|
|
||||||
receiveDerivation = receiveDerivations["$j"];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// receiveDerivation = receiveDerivations[addresses[i]];
|
if (changeDerivation != null) {
|
||||||
// if a match exists it will not be null
|
pubKey = changeDerivation["publicKey"] as String;
|
||||||
if (receiveDerivation != null) {
|
wif = changeDerivation["wif"] as String;
|
||||||
final data = P2PKH(
|
}
|
||||||
data: PaymentData(
|
}
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["publicKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addresses[i]]!) {
|
if (wif == null || pubKey == null) {
|
||||||
results[tx] = {
|
final address = await db.getAddress(walletId, sd.utxo.address!);
|
||||||
"output": data.output,
|
if (address?.derivationPath != null) {
|
||||||
"keyPair": ECPair.fromWIF(
|
final node = await Bip32Utils.getBip32Node(
|
||||||
receiveDerivation["wif"] as String,
|
(await mnemonicString)!,
|
||||||
network: _network,
|
(await mnemonicPassphrase)!,
|
||||||
),
|
_network,
|
||||||
};
|
address!.derivationPath!.value,
|
||||||
}
|
);
|
||||||
} else {
|
|
||||||
// if its not a receive, check change
|
|
||||||
|
|
||||||
dynamic changeDerivation;
|
wif = node.toWIF();
|
||||||
|
pubKey = Format.uint8listToString(node.publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int j = 0; j < changeDerivations.length; j++) {
|
if (wif != null && pubKey != null) {
|
||||||
if (changeDerivations["$j"]["address"] == addresses[i]) {
|
final PaymentData data;
|
||||||
changeDerivation = changeDerivations["$j"];
|
final Uint8List? redeemScript;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// final changeDerivation = changeDerivations[addresses[i]];
|
switch (sd.derivePathType) {
|
||||||
// if a match exists it will not be null
|
case DerivePathType.bip44:
|
||||||
if (changeDerivation != null) {
|
data = P2PKH(
|
||||||
final data = P2PKH(
|
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["publicKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addresses[i]]!) {
|
default:
|
||||||
results[tx] = {
|
throw Exception("DerivePathType unsupported");
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final keyPair = ECPair.fromWIF(
|
||||||
|
wif,
|
||||||
|
network: _network,
|
||||||
|
);
|
||||||
|
|
||||||
|
sd.redeemScript = redeemScript;
|
||||||
|
sd.output = data.output;
|
||||||
|
sd.keyPair = keyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return signingData;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
|
@ -1751,8 +1766,7 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
|
|
||||||
/// Builds and signs a transaction
|
/// Builds and signs a transaction
|
||||||
Future<Map<String, dynamic>> buildTransaction({
|
Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<isar_models.UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -1763,10 +1777,14 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
txb.addInput(
|
||||||
utxoSigningData[txid]["output"] as Uint8List);
|
txid,
|
||||||
|
utxoSigningData[i].utxo.vout,
|
||||||
|
null,
|
||||||
|
utxoSigningData[i].output!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add transaction output
|
// Add transaction output
|
||||||
|
@ -1776,13 +1794,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sign the transaction accordingly
|
// Sign the transaction accordingly
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
|
||||||
txb.sign(
|
txb.sign(
|
||||||
vin: i,
|
vin: i,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
keyPair: utxoSigningData[i].keyPair!,
|
||||||
witnessValue: utxosToUse[i].value,
|
witnessValue: utxoSigningData[i].utxo.value,
|
||||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
redeemScript: utxoSigningData[i].redeemScript,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||||
import 'package:stackwallet/models/balance.dart';
|
import 'package:stackwallet/models/balance.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -1058,13 +1059,15 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool coinControl = utxos != null;
|
||||||
|
|
||||||
final txData = await coinSelection(
|
final txData = await coinSelection(
|
||||||
satoshiAmountToSend: satoshiAmount,
|
satoshiAmountToSend: satoshiAmount,
|
||||||
selectedTxFeeRate: rate,
|
selectedTxFeeRate: rate,
|
||||||
recipientAddress: address,
|
recipientAddress: address,
|
||||||
isSendAll: isSendAll,
|
isSendAll: isSendAll,
|
||||||
utxos: utxos?.toList(),
|
utxos: utxos?.toList(),
|
||||||
coinControl: utxos is List<isar_models.UTXO>,
|
coinControl: coinControl,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||||
|
@ -2314,6 +2317,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
} else {
|
} else {
|
||||||
satoshisBeingUsed = spendableSatoshiValue;
|
satoshisBeingUsed = spendableSatoshiValue;
|
||||||
utxoObjectsToUse = spendableOutputs;
|
utxoObjectsToUse = spendableOutputs;
|
||||||
|
inputsBeingConsumed = spendableOutputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2335,7 +2339,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -2353,7 +2356,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: [amount],
|
satoshiAmounts: [amount],
|
||||||
|
@ -2364,19 +2366,17 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": amount,
|
"recipientAmt": amount,
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
))["vSize"] as int;
|
))["vSize"] as int;
|
||||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [
|
recipients: [
|
||||||
recipientAddress,
|
recipientAddress,
|
||||||
|
@ -2442,7 +2442,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2470,7 +2469,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2483,7 +2481,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2500,7 +2498,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2511,7 +2508,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2530,7 +2527,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2541,7 +2537,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2560,7 +2556,6 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2571,7 +2566,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2597,245 +2592,146 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
Future<List<SigningData>> fetchBuildTxData(
|
||||||
List<isar_models.UTXO> utxosToUse,
|
List<isar_models.UTXO> utxosToUse,
|
||||||
) async {
|
) async {
|
||||||
// return data
|
// return data
|
||||||
Map<String, dynamic> results = {};
|
List<SigningData> signingData = [];
|
||||||
Map<String, List<String>> addressTxid = {};
|
|
||||||
|
|
||||||
// addresses to check
|
|
||||||
List<String> addressesP2PKH = [];
|
|
||||||
List<String> addressesP2SH = [];
|
|
||||||
List<String> addressesP2WPKH = [];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Populating the addresses to check
|
// Populating the addresses to check
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
if (utxosToUse[i].address == null) {
|
||||||
final tx = await _cachedElectrumXClient.getTransaction(
|
final txid = utxosToUse[i].txid;
|
||||||
txHash: txid,
|
final tx = await _cachedElectrumXClient.getTransaction(
|
||||||
coin: coin,
|
txHash: txid,
|
||||||
);
|
coin: coin,
|
||||||
|
);
|
||||||
for (final output in tx["vout"] as List) {
|
for (final output in tx["vout"] as List) {
|
||||||
final n = output["n"];
|
final n = output["n"];
|
||||||
if (n != null && n == utxosToUse[i].vout) {
|
if (n != null && n == utxosToUse[i].vout) {
|
||||||
final address = output["scriptPubKey"]["addresses"][0] as String;
|
utxosToUse[i] = utxosToUse[i].copyWith(
|
||||||
if (!addressTxid.containsKey(address)) {
|
address: output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
addressTxid[address] = <String>[];
|
output["scriptPubKey"]["address"] as String,
|
||||||
}
|
);
|
||||||
(addressTxid[address] as List).add(txid);
|
|
||||||
switch (addressType(address: address)) {
|
|
||||||
case DerivePathType.bip44:
|
|
||||||
addressesP2PKH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip49:
|
|
||||||
addressesP2SH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip84:
|
|
||||||
addressesP2WPKH.add(address);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception("DerivePathType unsupported");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||||
|
|
||||||
|
signingData.add(
|
||||||
|
SigningData(
|
||||||
|
derivePathType: derivePathType,
|
||||||
|
utxo: utxosToUse[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// p2pkh / bip44
|
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||||
final p2pkhLength = addressesP2PKH.length;
|
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||||
if (p2pkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2pkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2PKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
for (final sd in signingData) {
|
||||||
results[tx] = {
|
String? pubKey;
|
||||||
"output": data.output,
|
String? wif;
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
// fetch receiving derivations if null
|
||||||
network: _network,
|
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
),
|
chain: 0,
|
||||||
};
|
derivePathType: sd.derivePathType,
|
||||||
}
|
);
|
||||||
} else {
|
final receiveDerivation =
|
||||||
// if its not a receive, check change
|
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
final changeDerivation = changeDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
if (receiveDerivation != null) {
|
||||||
if (changeDerivation != null) {
|
pubKey = receiveDerivation["pubKey"] as String;
|
||||||
final data = P2PKH(
|
wif = receiveDerivation["wif"] as String;
|
||||||
|
} else {
|
||||||
|
// fetch change derivations if null
|
||||||
|
changeDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
|
chain: 1,
|
||||||
|
derivePathType: sd.derivePathType,
|
||||||
|
);
|
||||||
|
final changeDerivation =
|
||||||
|
changeDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
|
if (changeDerivation != null) {
|
||||||
|
pubKey = changeDerivation["pubKey"] as String;
|
||||||
|
wif = changeDerivation["wif"] as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif == null || pubKey == null) {
|
||||||
|
final address = await db.getAddress(walletId, sd.utxo.address!);
|
||||||
|
if (address?.derivationPath != null) {
|
||||||
|
final node = await Bip32Utils.getBip32Node(
|
||||||
|
(await mnemonicString)!,
|
||||||
|
(await mnemonicPassphrase)!,
|
||||||
|
_network,
|
||||||
|
address!.derivationPath!.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
wif = node.toWIF();
|
||||||
|
pubKey = Format.uint8listToString(node.publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif != null && pubKey != null) {
|
||||||
|
final PaymentData data;
|
||||||
|
final Uint8List? redeemScript;
|
||||||
|
|
||||||
|
switch (sd.derivePathType) {
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
data = P2PKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
case DerivePathType.bip49:
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2sh / bip49
|
|
||||||
final p2shLength = addressesP2SH.length;
|
|
||||||
if (p2shLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip49,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip49,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2shLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2SH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final p2wpkh = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: _network.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
final redeemScript = p2wpkh.output;
|
|
||||||
|
|
||||||
final data =
|
|
||||||
P2SH(data: PaymentData(redeem: p2wpkh), network: _network).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2SH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
"redeemScript": redeemScript,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if its not a receive, check change
|
|
||||||
final changeDerivation = changeDerivations[addressesP2SH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (changeDerivation != null) {
|
|
||||||
final p2wpkh = P2WPKH(
|
final p2wpkh = P2WPKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: _network.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
final redeemScript = p2wpkh.output;
|
|
||||||
|
|
||||||
final data =
|
|
||||||
P2SH(data: PaymentData(redeem: p2wpkh), network: _network)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2SH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
"redeemScript": redeemScript,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2wpkh / bip84
|
|
||||||
final p2wpkhLength = addressesP2WPKH.length;
|
|
||||||
if (p2wpkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < p2wpkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2WPKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: _network.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
),
|
||||||
};
|
network: _network,
|
||||||
}
|
overridePrefix: _network.bech32!,
|
||||||
} else {
|
).data;
|
||||||
// if its not a receive, check change
|
redeemScript = p2wpkh.output;
|
||||||
final changeDerivation = changeDerivations[addressesP2WPKH[i]];
|
data = P2SH(
|
||||||
// if a match exists it will not be null
|
data: PaymentData(redeem: p2wpkh),
|
||||||
if (changeDerivation != null) {
|
network: _network,
|
||||||
final data = P2WPKH(
|
).data;
|
||||||
data: PaymentData(
|
break;
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
changeDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: _network.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
case DerivePathType.bip84:
|
||||||
results[tx] = {
|
data = P2WPKH(
|
||||||
"output": data.output,
|
data: PaymentData(
|
||||||
"keyPair": ECPair.fromWIF(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["wif"] as String,
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
),
|
overridePrefix: _network.bech32!,
|
||||||
};
|
).data;
|
||||||
}
|
redeemScript = null;
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Exception("DerivePathType unsupported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final keyPair = ECPair.fromWIF(
|
||||||
|
wif,
|
||||||
|
network: _network,
|
||||||
|
);
|
||||||
|
|
||||||
|
sd.redeemScript = redeemScript;
|
||||||
|
sd.output = data.output;
|
||||||
|
sd.keyPair = keyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return signingData;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
|
@ -2845,8 +2741,7 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
/// Builds and signs a transaction
|
/// Builds and signs a transaction
|
||||||
Future<Map<String, dynamic>> buildTransaction({
|
Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<isar_models.UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -2857,10 +2752,15 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
txb.setVersion(1);
|
txb.setVersion(1);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
txb.addInput(
|
||||||
utxoSigningData[txid]["output"] as Uint8List, _network.bech32!);
|
txid,
|
||||||
|
utxoSigningData[i].utxo.vout,
|
||||||
|
null,
|
||||||
|
utxoSigningData[i].output!,
|
||||||
|
_network.bech32!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add transaction output
|
// Add transaction output
|
||||||
|
@ -2870,14 +2770,14 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sign the transaction accordingly
|
// Sign the transaction accordingly
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
|
||||||
txb.sign(
|
txb.sign(
|
||||||
vin: i,
|
vin: i,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
keyPair: utxoSigningData[i].keyPair!,
|
||||||
witnessValue: utxosToUse[i].value,
|
witnessValue: utxoSigningData[i].utxo.value,
|
||||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
redeemScript: utxoSigningData[i].redeemScript,
|
||||||
overridePrefix: _network.bech32!);
|
overridePrefix: _network.bech32!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
||||||
|
|
|
@ -17,6 +17,7 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||||
import 'package:stackwallet/models/balance.dart';
|
import 'package:stackwallet/models/balance.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -1049,13 +1050,15 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool coinControl = utxos != null;
|
||||||
|
|
||||||
final txData = await coinSelection(
|
final txData = await coinSelection(
|
||||||
satoshiAmountToSend: satoshiAmount,
|
satoshiAmountToSend: satoshiAmount,
|
||||||
selectedTxFeeRate: rate,
|
selectedTxFeeRate: rate,
|
||||||
recipientAddress: address,
|
recipientAddress: address,
|
||||||
isSendAll: isSendAll,
|
isSendAll: isSendAll,
|
||||||
utxos: utxos?.toList(),
|
utxos: utxos?.toList(),
|
||||||
coinControl: utxos is List<isar_models.UTXO>,
|
coinControl: coinControl,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||||
|
@ -2307,6 +2310,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
} else {
|
} else {
|
||||||
satoshisBeingUsed = spendableSatoshiValue;
|
satoshisBeingUsed = spendableSatoshiValue;
|
||||||
utxoObjectsToUse = spendableOutputs;
|
utxoObjectsToUse = spendableOutputs;
|
||||||
|
inputsBeingConsumed = spendableOutputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2328,7 +2332,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -2346,7 +2349,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: [amount],
|
satoshiAmounts: [amount],
|
||||||
|
@ -2357,19 +2359,17 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": amount,
|
"recipientAmt": amount,
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
))["vSize"] as int;
|
))["vSize"] as int;
|
||||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [
|
recipients: [
|
||||||
recipientAddress,
|
recipientAddress,
|
||||||
|
@ -2435,7 +2435,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2463,7 +2462,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2476,7 +2474,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2493,7 +2491,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2504,7 +2501,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2523,7 +2520,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2534,7 +2530,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2553,7 +2549,6 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2564,7 +2559,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2590,248 +2585,144 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
Future<List<SigningData>> fetchBuildTxData(
|
||||||
List<isar_models.UTXO> utxosToUse,
|
List<isar_models.UTXO> utxosToUse,
|
||||||
) async {
|
) async {
|
||||||
// return data
|
// return data
|
||||||
Map<String, dynamic> results = {};
|
List<SigningData> signingData = [];
|
||||||
Map<String, List<String>> addressTxid = {};
|
|
||||||
|
|
||||||
// addresses to check
|
|
||||||
List<String> addressesP2PKH = [];
|
|
||||||
List<String> addressesP2SH = [];
|
|
||||||
List<String> addressesP2WPKH = [];
|
|
||||||
Logging.instance.log("utxos: $utxosToUse", level: LogLevel.Info);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Populating the addresses to check
|
// Populating the addresses to check
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
if (utxosToUse[i].address == null) {
|
||||||
final tx = await _cachedElectrumXClient.getTransaction(
|
final txid = utxosToUse[i].txid;
|
||||||
txHash: txid,
|
final tx = await _cachedElectrumXClient.getTransaction(
|
||||||
coin: coin,
|
txHash: txid,
|
||||||
);
|
coin: coin,
|
||||||
Logging.instance.log("tx: ${json.encode(tx)}",
|
);
|
||||||
level: LogLevel.Info, printFullLength: true);
|
for (final output in tx["vout"] as List) {
|
||||||
|
final n = output["n"];
|
||||||
for (final output in tx["vout"] as List) {
|
if (n != null && n == utxosToUse[i].vout) {
|
||||||
final n = output["n"];
|
utxosToUse[i] = utxosToUse[i].copyWith(
|
||||||
if (n != null && n == utxosToUse[i].vout) {
|
address: output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
final address = output["scriptPubKey"]["address"] as String;
|
output["scriptPubKey"]["address"] as String,
|
||||||
if (!addressTxid.containsKey(address)) {
|
);
|
||||||
addressTxid[address] = <String>[];
|
|
||||||
}
|
|
||||||
(addressTxid[address] as List).add(txid);
|
|
||||||
switch (addressType(address: address)) {
|
|
||||||
case DerivePathType.bip44:
|
|
||||||
addressesP2PKH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip49:
|
|
||||||
addressesP2SH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip84:
|
|
||||||
addressesP2WPKH.add(address);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception("DerivePathType unsupported");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||||
|
|
||||||
|
signingData.add(
|
||||||
|
SigningData(
|
||||||
|
derivePathType: derivePathType,
|
||||||
|
utxo: utxosToUse[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// p2pkh / bip44
|
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||||
final p2pkhLength = addressesP2PKH.length;
|
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||||
if (p2pkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2pkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2PKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
for (final sd in signingData) {
|
||||||
results[tx] = {
|
String? pubKey;
|
||||||
"output": data.output,
|
String? wif;
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
// fetch receiving derivations if null
|
||||||
network: _network,
|
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
),
|
chain: 0,
|
||||||
};
|
derivePathType: sd.derivePathType,
|
||||||
}
|
);
|
||||||
} else {
|
final receiveDerivation =
|
||||||
// if its not a receive, check change
|
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
final changeDerivation = changeDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
if (receiveDerivation != null) {
|
||||||
if (changeDerivation != null) {
|
pubKey = receiveDerivation["pubKey"] as String;
|
||||||
final data = P2PKH(
|
wif = receiveDerivation["wif"] as String;
|
||||||
|
} else {
|
||||||
|
// fetch change derivations if null
|
||||||
|
changeDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
|
chain: 1,
|
||||||
|
derivePathType: sd.derivePathType,
|
||||||
|
);
|
||||||
|
final changeDerivation =
|
||||||
|
changeDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
|
if (changeDerivation != null) {
|
||||||
|
pubKey = changeDerivation["pubKey"] as String;
|
||||||
|
wif = changeDerivation["wif"] as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif == null || pubKey == null) {
|
||||||
|
final address = await db.getAddress(walletId, sd.utxo.address!);
|
||||||
|
if (address?.derivationPath != null) {
|
||||||
|
final node = await Bip32Utils.getBip32Node(
|
||||||
|
(await mnemonicString)!,
|
||||||
|
(await mnemonicPassphrase)!,
|
||||||
|
_network,
|
||||||
|
address!.derivationPath!.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
wif = node.toWIF();
|
||||||
|
pubKey = Format.uint8listToString(node.publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif != null && pubKey != null) {
|
||||||
|
final PaymentData data;
|
||||||
|
final Uint8List? redeemScript;
|
||||||
|
|
||||||
|
switch (sd.derivePathType) {
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
data = P2PKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
case DerivePathType.bip49:
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2sh / bip49
|
|
||||||
final p2shLength = addressesP2SH.length;
|
|
||||||
if (p2shLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip49,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip49,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2shLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2SH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final p2wpkh = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: namecoin.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
final redeemScript = p2wpkh.output;
|
|
||||||
|
|
||||||
final data =
|
|
||||||
P2SH(data: PaymentData(redeem: p2wpkh), network: _network).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2SH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
"redeemScript": redeemScript,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if its not a receive, check change
|
|
||||||
final changeDerivation = changeDerivations[addressesP2SH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (changeDerivation != null) {
|
|
||||||
final p2wpkh = P2WPKH(
|
final p2wpkh = P2WPKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: namecoin.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
final redeemScript = p2wpkh.output;
|
|
||||||
|
|
||||||
final data =
|
|
||||||
P2SH(data: PaymentData(redeem: p2wpkh), network: _network)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2SH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
"redeemScript": redeemScript,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2wpkh / bip84
|
|
||||||
final p2wpkhLength = addressesP2WPKH.length;
|
|
||||||
if (p2wpkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < p2wpkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2WPKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: namecoin.bech32!)
|
|
||||||
.data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
),
|
||||||
};
|
network: _network,
|
||||||
}
|
overridePrefix: _network.bech32!,
|
||||||
} else {
|
).data;
|
||||||
// if its not a receive, check change
|
redeemScript = p2wpkh.output;
|
||||||
final changeDerivation = changeDerivations[addressesP2WPKH[i]];
|
data = P2SH(data: PaymentData(redeem: p2wpkh), network: _network)
|
||||||
// if a match exists it will not be null
|
|
||||||
if (changeDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
changeDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
overridePrefix: namecoin.bech32!)
|
|
||||||
.data;
|
.data;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
case DerivePathType.bip84:
|
||||||
results[tx] = {
|
data = P2WPKH(
|
||||||
"output": data.output,
|
data: PaymentData(
|
||||||
"keyPair": ECPair.fromWIF(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["wif"] as String,
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
),
|
overridePrefix: _network.bech32!,
|
||||||
};
|
).data;
|
||||||
}
|
redeemScript = null;
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw Exception("DerivePathType unsupported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final keyPair = ECPair.fromWIF(
|
||||||
|
wif,
|
||||||
|
network: _network,
|
||||||
|
);
|
||||||
|
|
||||||
|
sd.redeemScript = redeemScript;
|
||||||
|
sd.output = data.output;
|
||||||
|
sd.keyPair = keyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return signingData;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
|
@ -2841,8 +2732,7 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
/// Builds and signs a transaction
|
/// Builds and signs a transaction
|
||||||
Future<Map<String, dynamic>> buildTransaction({
|
Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<isar_models.UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -2853,10 +2743,15 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
txb.setVersion(2);
|
txb.setVersion(2);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
txb.addInput(
|
||||||
utxoSigningData[txid]["output"] as Uint8List, namecoin.bech32!);
|
txid,
|
||||||
|
utxoSigningData[i].utxo.vout,
|
||||||
|
null,
|
||||||
|
utxoSigningData[i].output!,
|
||||||
|
_network.bech32!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add transaction output
|
// Add transaction output
|
||||||
|
@ -2866,14 +2761,15 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sign the transaction accordingly
|
// Sign the transaction accordingly
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
txb.sign(
|
txb.addInput(
|
||||||
vin: i,
|
txid,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
utxoSigningData[i].utxo.vout,
|
||||||
witnessValue: utxosToUse[i].value,
|
null,
|
||||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
utxoSigningData[i].output!,
|
||||||
overridePrefix: namecoin.bech32!);
|
_network.bech32!,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
||||||
|
|
|
@ -17,6 +17,7 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||||
import 'package:stackwallet/models/balance.dart';
|
import 'package:stackwallet/models/balance.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/refresh_percent_changed_event.dart';
|
||||||
|
@ -976,13 +977,15 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
isSendAll = true;
|
isSendAll = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final bool coinControl = utxos != null;
|
||||||
|
|
||||||
final txData = await coinSelection(
|
final txData = await coinSelection(
|
||||||
satoshiAmountToSend: satoshiAmount,
|
satoshiAmountToSend: satoshiAmount,
|
||||||
selectedTxFeeRate: rate,
|
selectedTxFeeRate: rate,
|
||||||
recipientAddress: address,
|
recipientAddress: address,
|
||||||
isSendAll: isSendAll,
|
isSendAll: isSendAll,
|
||||||
utxos: utxos?.toList(),
|
utxos: utxos?.toList(),
|
||||||
coinControl: utxos is List<isar_models.UTXO>,
|
coinControl: coinControl,
|
||||||
);
|
);
|
||||||
|
|
||||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||||
|
@ -2468,6 +2471,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
} else {
|
} else {
|
||||||
satoshisBeingUsed = spendableSatoshiValue;
|
satoshisBeingUsed = spendableSatoshiValue;
|
||||||
utxoObjectsToUse = spendableOutputs;
|
utxoObjectsToUse = spendableOutputs;
|
||||||
|
inputsBeingConsumed = spendableOutputs.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logging.instance
|
Logging.instance
|
||||||
|
@ -2489,7 +2493,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
|
@ -2507,7 +2510,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
|
|
||||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: [amount],
|
satoshiAmounts: [amount],
|
||||||
|
@ -2518,19 +2520,17 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
"recipientAmt": amount,
|
"recipientAmt": amount,
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int vSizeForOneOutput = (await buildTransaction(
|
final int vSizeForOneOutput = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [recipientAddress],
|
recipients: [recipientAddress],
|
||||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||||
))["vSize"] as int;
|
))["vSize"] as int;
|
||||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: [
|
recipients: [
|
||||||
recipientAddress,
|
recipientAddress,
|
||||||
|
@ -2596,7 +2596,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2624,7 +2623,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||||
level: LogLevel.Info);
|
level: LogLevel.Info);
|
||||||
txn = await buildTransaction(
|
txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2637,7 +2635,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2654,7 +2652,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2665,7 +2662,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2684,7 +2681,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2695,7 +2691,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -2714,7 +2710,6 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||||
dynamic txn = await buildTransaction(
|
dynamic txn = await buildTransaction(
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
recipients: recipientsArray,
|
recipients: recipientsArray,
|
||||||
satoshiAmounts: recipientsAmtArray,
|
satoshiAmounts: recipientsAmtArray,
|
||||||
|
@ -2725,7 +2720,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
"recipientAmt": recipientsAmtArray[0],
|
"recipientAmt": recipientsAmtArray[0],
|
||||||
"fee": feeForOneOutput,
|
"fee": feeForOneOutput,
|
||||||
"vSize": txn["vSize"],
|
"vSize": txn["vSize"],
|
||||||
"usedUTXOs": utxoObjectsToUse,
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2751,168 +2746,130 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
Future<List<SigningData>> fetchBuildTxData(
|
||||||
List<isar_models.UTXO> utxosToUse,
|
List<isar_models.UTXO> utxosToUse,
|
||||||
) async {
|
) async {
|
||||||
// return data
|
// return data
|
||||||
Map<String, dynamic> results = {};
|
List<SigningData> signingData = [];
|
||||||
Map<String, List<String>> addressTxid = {};
|
|
||||||
|
|
||||||
// addresses to check
|
|
||||||
List<String> addressesP2PKH = [];
|
|
||||||
List<String> addressesP2WPKH = [];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Populating the addresses to check
|
// Populating the addresses to check
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxosToUse.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
if (utxosToUse[i].address == null) {
|
||||||
final tx = await _cachedElectrumXClient.getTransaction(
|
final txid = utxosToUse[i].txid;
|
||||||
txHash: txid,
|
final tx = await _cachedElectrumXClient.getTransaction(
|
||||||
coin: coin,
|
txHash: txid,
|
||||||
);
|
coin: coin,
|
||||||
|
);
|
||||||
for (final output in tx["vout"] as List) {
|
for (final output in tx["vout"] as List) {
|
||||||
final n = output["n"];
|
final n = output["n"];
|
||||||
if (n != null && n == utxosToUse[i].vout) {
|
if (n != null && n == utxosToUse[i].vout) {
|
||||||
final address = output["scriptPubKey"]["addresses"][0] as String;
|
utxosToUse[i] = utxosToUse[i].copyWith(
|
||||||
if (!addressTxid.containsKey(address)) {
|
address: output["scriptPubKey"]?["addresses"]?[0] as String? ??
|
||||||
addressTxid[address] = <String>[];
|
output["scriptPubKey"]["address"] as String,
|
||||||
}
|
);
|
||||||
(addressTxid[address] as List).add(txid);
|
|
||||||
switch (addressType(address: address)) {
|
|
||||||
case DerivePathType.bip44:
|
|
||||||
addressesP2PKH.add(address);
|
|
||||||
break;
|
|
||||||
case DerivePathType.bip84:
|
|
||||||
addressesP2WPKH.add(address);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Exception(
|
|
||||||
"DerivePathType ${addressType(address: address)} not supported");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||||
|
|
||||||
|
signingData.add(
|
||||||
|
SigningData(
|
||||||
|
derivePathType: derivePathType,
|
||||||
|
utxo: utxosToUse[i],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// p2pkh / bip44
|
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||||
final p2pkhLength = addressesP2PKH.length;
|
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||||
if (p2pkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip44,
|
|
||||||
);
|
|
||||||
for (int i = 0; i < p2pkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2PKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
for (final sd in signingData) {
|
||||||
results[tx] = {
|
String? pubKey;
|
||||||
"output": data.output,
|
String? wif;
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
// fetch receiving derivations if null
|
||||||
network: _network,
|
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
),
|
chain: 0,
|
||||||
};
|
derivePathType: sd.derivePathType,
|
||||||
}
|
);
|
||||||
} else {
|
final receiveDerivation =
|
||||||
// if its not a receive, check change
|
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
final changeDerivation = changeDerivations[addressesP2PKH[i]];
|
|
||||||
// if a match exists it will not be null
|
if (receiveDerivation != null) {
|
||||||
if (changeDerivation != null) {
|
pubKey = receiveDerivation["pubKey"] as String;
|
||||||
final data = P2PKH(
|
wif = receiveDerivation["wif"] as String;
|
||||||
|
} else {
|
||||||
|
// fetch change derivations if null
|
||||||
|
changeDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||||
|
chain: 1,
|
||||||
|
derivePathType: sd.derivePathType,
|
||||||
|
);
|
||||||
|
final changeDerivation =
|
||||||
|
changeDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||||
|
if (changeDerivation != null) {
|
||||||
|
pubKey = changeDerivation["pubKey"] as String;
|
||||||
|
wif = changeDerivation["wif"] as String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif == null || pubKey == null) {
|
||||||
|
final address = await db.getAddress(walletId, sd.utxo.address!);
|
||||||
|
if (address?.derivationPath != null) {
|
||||||
|
final node = await Bip32Utils.getBip32Node(
|
||||||
|
(await mnemonicString)!,
|
||||||
|
(await mnemonicPassphrase)!,
|
||||||
|
_network,
|
||||||
|
address!.derivationPath!.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
wif = node.toWIF();
|
||||||
|
pubKey = Format.uint8listToString(node.publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wif != null && pubKey != null) {
|
||||||
|
final PaymentData data;
|
||||||
|
final Uint8List? redeemScript;
|
||||||
|
|
||||||
|
switch (sd.derivePathType) {
|
||||||
|
case DerivePathType.bip44:
|
||||||
|
data = P2PKH(
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
case DerivePathType.bip84:
|
||||||
results[tx] = {
|
data = P2WPKH(
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// p2wpkh / bip84
|
|
||||||
final p2wpkhLength = addressesP2WPKH.length;
|
|
||||||
if (p2wpkhLength > 0) {
|
|
||||||
final receiveDerivations = await _fetchDerivations(
|
|
||||||
chain: 0,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
final changeDerivations = await _fetchDerivations(
|
|
||||||
chain: 1,
|
|
||||||
derivePathType: DerivePathType.bip84,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < p2wpkhLength; i++) {
|
|
||||||
// receives
|
|
||||||
final receiveDerivation = receiveDerivations[addressesP2WPKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (receiveDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
|
||||||
pubkey: Format.stringToUint8List(
|
|
||||||
receiveDerivation["pubKey"] as String)),
|
|
||||||
network: _network,
|
|
||||||
).data;
|
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
|
||||||
results[tx] = {
|
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
receiveDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// if its not a receive, check change
|
|
||||||
final changeDerivation = changeDerivations[addressesP2WPKH[i]];
|
|
||||||
// if a match exists it will not be null
|
|
||||||
if (changeDerivation != null) {
|
|
||||||
final data = P2WPKH(
|
|
||||||
data: PaymentData(
|
data: PaymentData(
|
||||||
pubkey: Format.stringToUint8List(
|
pubkey: Format.stringToUint8List(pubKey),
|
||||||
changeDerivation["pubKey"] as String)),
|
),
|
||||||
network: _network,
|
network: _network,
|
||||||
).data;
|
).data;
|
||||||
|
redeemScript = null;
|
||||||
|
break;
|
||||||
|
|
||||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
default:
|
||||||
results[tx] = {
|
throw Exception("DerivePathType unsupported");
|
||||||
"output": data.output,
|
|
||||||
"keyPair": ECPair.fromWIF(
|
|
||||||
changeDerivation["wif"] as String,
|
|
||||||
network: _network,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final keyPair = ECPair.fromWIF(
|
||||||
|
wif,
|
||||||
|
network: _network,
|
||||||
|
);
|
||||||
|
|
||||||
|
sd.redeemScript = redeemScript;
|
||||||
|
sd.output = data.output;
|
||||||
|
sd.keyPair = keyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logging.instance.log("FETCHED TX BUILD DATA IS -----$results",
|
|
||||||
level: LogLevel.Info, printFullLength: true);
|
return signingData;
|
||||||
return results;
|
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance
|
Logging.instance
|
||||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||||
|
@ -2922,8 +2879,7 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
|
|
||||||
/// Builds and signs a transaction
|
/// Builds and signs a transaction
|
||||||
Future<Map<String, dynamic>> buildTransaction({
|
Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<isar_models.UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required List<String> recipients,
|
required List<String> recipients,
|
||||||
required List<int> satoshiAmounts,
|
required List<int> satoshiAmounts,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -2937,11 +2893,15 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
txb.setVersion(160);
|
txb.setVersion(160);
|
||||||
|
|
||||||
// Add transaction inputs
|
// Add transaction inputs
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
final txid = utxoSigningData[i].utxo.txid;
|
||||||
|
txb.addInput(
|
||||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
txid,
|
||||||
utxoSigningData[txid]["output"] as Uint8List, '');
|
utxoSigningData[i].utxo.vout,
|
||||||
|
null,
|
||||||
|
utxoSigningData[i].output!,
|
||||||
|
'',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add transaction output
|
// Add transaction output
|
||||||
|
@ -2951,13 +2911,13 @@ class ParticlWallet extends CoinServiceAPI
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Sign the transaction accordingly
|
// Sign the transaction accordingly
|
||||||
for (var i = 0; i < utxosToUse.length; i++) {
|
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
|
||||||
txb.sign(
|
txb.sign(
|
||||||
vin: i,
|
vin: i,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
keyPair: utxoSigningData[i].keyPair!,
|
||||||
witnessValue: utxosToUse[i].value,
|
witnessValue: utxoSigningData[i].utxo.value,
|
||||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?);
|
redeemScript: utxoSigningData[i].redeemScript,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
Logging.instance.log("Caught exception while signing transaction: $e\n$s",
|
||||||
|
|
|
@ -15,6 +15,7 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||||
import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dart';
|
import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dart';
|
||||||
import 'package:stackwallet/exceptions/wallet/paynym_send_exception.dart';
|
import 'package:stackwallet/exceptions/wallet/paynym_send_exception.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
|
import 'package:stackwallet/models/signing_data.dart';
|
||||||
import 'package:stackwallet/utilities/bip32_utils.dart';
|
import 'package:stackwallet/utilities/bip32_utils.dart';
|
||||||
import 'package:stackwallet/utilities/bip47_utils.dart';
|
import 'package:stackwallet/utilities/bip47_utils.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
@ -57,7 +58,7 @@ mixin PaynymWalletInterface {
|
||||||
late final Future<int> Function({
|
late final Future<int> Function({
|
||||||
required String address,
|
required String address,
|
||||||
}) _getTxCount;
|
}) _getTxCount;
|
||||||
late final Future<Map<String, dynamic>> Function(
|
late final Future<List<SigningData>> Function(
|
||||||
List<UTXO> utxosToUse,
|
List<UTXO> utxosToUse,
|
||||||
) _fetchBuildTxData;
|
) _fetchBuildTxData;
|
||||||
late final Future<void> Function() _refresh;
|
late final Future<void> Function() _refresh;
|
||||||
|
@ -100,7 +101,7 @@ mixin PaynymWalletInterface {
|
||||||
required String address,
|
required String address,
|
||||||
})
|
})
|
||||||
getTxCount,
|
getTxCount,
|
||||||
required Future<Map<String, dynamic>> Function(
|
required Future<List<SigningData>> Function(
|
||||||
List<UTXO> utxosToUse,
|
List<UTXO> utxosToUse,
|
||||||
)
|
)
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
|
@ -455,7 +456,6 @@ mixin PaynymWalletInterface {
|
||||||
|
|
||||||
final int vSizeForNoChange = (await _createNotificationTx(
|
final int vSizeForNoChange = (await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
change: 0,
|
change: 0,
|
||||||
dustLimit:
|
dustLimit:
|
||||||
|
@ -465,7 +465,6 @@ mixin PaynymWalletInterface {
|
||||||
|
|
||||||
final int vSizeForWithChange = (await _createNotificationTx(
|
final int vSizeForWithChange = (await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
change: satoshisBeingUsed - amountToSend,
|
change: satoshisBeingUsed - amountToSend,
|
||||||
))
|
))
|
||||||
|
@ -503,7 +502,6 @@ mixin PaynymWalletInterface {
|
||||||
feeForWithChange) {
|
feeForWithChange) {
|
||||||
var txn = await _createNotificationTx(
|
var txn = await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
change: changeAmount,
|
change: changeAmount,
|
||||||
);
|
);
|
||||||
|
@ -516,7 +514,6 @@ mixin PaynymWalletInterface {
|
||||||
feeBeingPaid += 1;
|
feeBeingPaid += 1;
|
||||||
txn = await _createNotificationTx(
|
txn = await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
change: changeAmount,
|
change: changeAmount,
|
||||||
);
|
);
|
||||||
|
@ -528,6 +525,7 @@ mixin PaynymWalletInterface {
|
||||||
"amount": amountToSend,
|
"amount": amountToSend,
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn.item2,
|
"vSize": txn.item2,
|
||||||
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -535,7 +533,6 @@ mixin PaynymWalletInterface {
|
||||||
// than the dust limit. Try without change
|
// than the dust limit. Try without change
|
||||||
final txn = await _createNotificationTx(
|
final txn = await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
change: 0,
|
change: 0,
|
||||||
);
|
);
|
||||||
|
@ -548,6 +545,7 @@ mixin PaynymWalletInterface {
|
||||||
"amount": amountToSend,
|
"amount": amountToSend,
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn.item2,
|
"vSize": txn.item2,
|
||||||
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
}
|
}
|
||||||
|
@ -556,7 +554,6 @@ mixin PaynymWalletInterface {
|
||||||
// build without change here
|
// build without change here
|
||||||
final txn = await _createNotificationTx(
|
final txn = await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
utxosToUse: utxoObjectsToUse,
|
|
||||||
utxoSigningData: utxoSigningData,
|
utxoSigningData: utxoSigningData,
|
||||||
change: 0,
|
change: 0,
|
||||||
);
|
);
|
||||||
|
@ -569,6 +566,7 @@ mixin PaynymWalletInterface {
|
||||||
"amount": amountToSend,
|
"amount": amountToSend,
|
||||||
"fee": feeBeingPaid,
|
"fee": feeBeingPaid,
|
||||||
"vSize": txn.item2,
|
"vSize": txn.item2,
|
||||||
|
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||||
};
|
};
|
||||||
return transactionObject;
|
return transactionObject;
|
||||||
} else {
|
} else {
|
||||||
|
@ -594,8 +592,7 @@ mixin PaynymWalletInterface {
|
||||||
// equal to its vSize
|
// equal to its vSize
|
||||||
Future<Tuple2<String, int>> _createNotificationTx({
|
Future<Tuple2<String, int>> _createNotificationTx({
|
||||||
required String targetPaymentCodeString,
|
required String targetPaymentCodeString,
|
||||||
required List<UTXO> utxosToUse,
|
required List<SigningData> utxoSigningData,
|
||||||
required Map<String, dynamic> utxoSigningData,
|
|
||||||
required int change,
|
required int change,
|
||||||
int? dustLimit,
|
int? dustLimit,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -604,7 +601,7 @@ mixin PaynymWalletInterface {
|
||||||
PaymentCode.fromPaymentCode(targetPaymentCodeString, _network);
|
PaymentCode.fromPaymentCode(targetPaymentCodeString, _network);
|
||||||
final myCode = await getPaymentCode(DerivePathType.bip44);
|
final myCode = await getPaymentCode(DerivePathType.bip44);
|
||||||
|
|
||||||
final utxo = utxosToUse.first;
|
final utxo = utxoSigningData.first.utxo;
|
||||||
final txPoint = utxo.txid.fromHex.reversed.toList();
|
final txPoint = utxo.txid.fromHex.reversed.toList();
|
||||||
final txPointIndex = utxo.vout;
|
final txPointIndex = utxo.vout;
|
||||||
|
|
||||||
|
@ -613,8 +610,7 @@ mixin PaynymWalletInterface {
|
||||||
final buffer = rev.buffer.asByteData();
|
final buffer = rev.buffer.asByteData();
|
||||||
buffer.setUint32(txPoint.length, txPointIndex, Endian.little);
|
buffer.setUint32(txPoint.length, txPointIndex, Endian.little);
|
||||||
|
|
||||||
final myKeyPair =
|
final myKeyPair = utxoSigningData.first.keyPair!;
|
||||||
utxoSigningData[utxo.txid]["keyPair"] as btc_dart.ECPair;
|
|
||||||
|
|
||||||
final S = SecretPoint(
|
final S = SecretPoint(
|
||||||
myKeyPair.privateKey!,
|
myKeyPair.privateKey!,
|
||||||
|
@ -642,17 +638,17 @@ mixin PaynymWalletInterface {
|
||||||
utxo.txid,
|
utxo.txid,
|
||||||
txPointIndex,
|
txPointIndex,
|
||||||
null,
|
null,
|
||||||
utxoSigningData[utxo.txid]["output"] as Uint8List,
|
utxoSigningData.first.output!,
|
||||||
);
|
);
|
||||||
|
|
||||||
// add rest of possible inputs
|
// add rest of possible inputs
|
||||||
for (var i = 1; i < utxosToUse.length; i++) {
|
for (var i = 1; i < utxoSigningData.length; i++) {
|
||||||
final utxo = utxosToUse[i];
|
final utxo = utxoSigningData[i].utxo;
|
||||||
txb.addInput(
|
txb.addInput(
|
||||||
utxo.txid,
|
utxo.txid,
|
||||||
utxo.vout,
|
utxo.vout,
|
||||||
null,
|
null,
|
||||||
utxoSigningData[utxo.txid]["output"] as Uint8List,
|
utxoSigningData[i].output!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,18 +671,16 @@ mixin PaynymWalletInterface {
|
||||||
vin: 0,
|
vin: 0,
|
||||||
keyPair: myKeyPair,
|
keyPair: myKeyPair,
|
||||||
witnessValue: utxo.value,
|
witnessValue: utxo.value,
|
||||||
witnessScript: utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?,
|
witnessScript: utxoSigningData.first.redeemScript,
|
||||||
);
|
);
|
||||||
|
|
||||||
// sign rest of possible inputs
|
// sign rest of possible inputs
|
||||||
for (var i = 1; i < utxosToUse.length; i++) {
|
for (var i = 1; i < utxoSigningData.length; i++) {
|
||||||
final txid = utxosToUse[i].txid;
|
|
||||||
txb.sign(
|
txb.sign(
|
||||||
vin: i,
|
vin: i,
|
||||||
keyPair: utxoSigningData[txid]["keyPair"] as btc_dart.ECPair,
|
keyPair: utxoSigningData[i].keyPair!,
|
||||||
witnessValue: utxosToUse[i].value,
|
witnessValue: utxoSigningData[i].utxo.value,
|
||||||
witnessScript:
|
witnessScript: utxoSigningData[i].redeemScript,
|
||||||
utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,20 +21,24 @@ class StackDialogBase extends StatelessWidget {
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
!Util.isDesktop ? MainAxisAlignment.end : MainAxisAlignment.center,
|
!Util.isDesktop ? MainAxisAlignment.end : MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Material(
|
Flexible(
|
||||||
borderRadius: BorderRadius.circular(
|
child: SingleChildScrollView(
|
||||||
20,
|
child: Material(
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
20,
|
20,
|
||||||
),
|
),
|
||||||
),
|
child: Container(
|
||||||
child: Padding(
|
decoration: BoxDecoration(
|
||||||
padding: padding,
|
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
child: child,
|
borderRadius: BorderRadius.circular(
|
||||||
|
20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: padding,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -12,7 +12,7 @@ sudo apt install -y unzip pkg-config clang cmake ninja-build libgtk-3-dev
|
||||||
cd $DEVELOPMENT
|
cd $DEVELOPMENT
|
||||||
git clone https://github.com/flutter/flutter.git
|
git clone https://github.com/flutter/flutter.git
|
||||||
cd flutter
|
cd flutter
|
||||||
git checkout 3.3.4
|
git checkout 3.7.6
|
||||||
export FLUTTER_DIR=$(pwd)/bin
|
export FLUTTER_DIR=$(pwd)/bin
|
||||||
echo 'export PATH="$PATH:'${FLUTTER_DIR}'"' >> ~/.bashrc
|
echo 'export PATH="$PATH:'${FLUTTER_DIR}'"' >> ~/.bashrc
|
||||||
source ~/.bashrc
|
source ~/.bashrc
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i22;
|
import 'dart:async' as _i22;
|
||||||
import 'dart:typed_data' as _i28;
|
import 'dart:typed_data' as _i29;
|
||||||
import 'dart:ui' as _i24;
|
import 'dart:ui' as _i24;
|
||||||
|
|
||||||
import 'package:bip32/bip32.dart' as _i17;
|
import 'package:bip32/bip32.dart' as _i17;
|
||||||
|
@ -20,19 +20,20 @@ import 'package:stackwallet/models/balance.dart' as _i12;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i16;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i16;
|
||||||
import 'package:stackwallet/models/node_model.dart' as _i25;
|
import 'package:stackwallet/models/node_model.dart' as _i25;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i9;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i9;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i28;
|
||||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i26;
|
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i26;
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
import 'package:stackwallet/services/locale_service.dart' as _i29;
|
import 'package:stackwallet/services/locale_service.dart' as _i30;
|
||||||
import 'package:stackwallet/services/node_service.dart' as _i3;
|
import 'package:stackwallet/services/node_service.dart' as _i3;
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||||
as _i8;
|
as _i8;
|
||||||
import 'package:stackwallet/services/wallets.dart' as _i20;
|
import 'package:stackwallet/services/wallets.dart' as _i20;
|
||||||
import 'package:stackwallet/services/wallets_service.dart' as _i2;
|
import 'package:stackwallet/services/wallets_service.dart' as _i2;
|
||||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i31;
|
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i32;
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i21;
|
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i21;
|
||||||
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i27;
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i27;
|
||||||
import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i30;
|
import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i31;
|
||||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
||||||
as _i7;
|
as _i7;
|
||||||
import 'package:stackwallet/utilities/prefs.dart' as _i23;
|
import 'package:stackwallet/utilities/prefs.dart' as _i23;
|
||||||
|
@ -1438,7 +1439,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i22.Future<List<_i28.SigningData>> fetchBuildTxData(
|
||||||
List<_i16.UTXO>? utxosToUse) =>
|
List<_i16.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -1446,12 +1447,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i22.Future<List<_i28.SigningData>>.value(<_i28.SigningData>[]),
|
||||||
) as _i22.Future<Map<String, dynamic>>);
|
) as _i22.Future<List<_i28.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i16.UTXO>? utxosToUse,
|
required List<_i28.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1460,7 +1460,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -1714,7 +1713,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
||||||
})?
|
})?
|
||||||
prepareSend,
|
prepareSend,
|
||||||
required _i22.Future<int> Function({required String address})? getTxCount,
|
required _i22.Future<int> Function({required String address})? getTxCount,
|
||||||
required _i22.Future<Map<String, dynamic>> Function(List<_i16.UTXO>)?
|
required _i22.Future<List<_i28.SigningData>> Function(List<_i16.UTXO>)?
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
required _i22.Future<void> Function()? refresh,
|
required _i22.Future<void> Function()? refresh,
|
||||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||||
|
@ -1866,14 +1865,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
||||||
)),
|
)),
|
||||||
) as _i22.Future<_i18.PaymentCode>);
|
) as _i22.Future<_i18.PaymentCode>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
_i22.Future<_i29.Uint8List> signWithNotificationKey(_i29.Uint8List? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#signWithNotificationKey,
|
#signWithNotificationKey,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
returnValue: _i22.Future<_i29.Uint8List>.value(_i29.Uint8List(0)),
|
||||||
) as _i22.Future<_i28.Uint8List>);
|
) as _i22.Future<_i29.Uint8List>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2209,7 +2208,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
||||||
/// A class which mocks [LocaleService].
|
/// A class which mocks [LocaleService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockLocaleService extends _i1.Mock implements _i29.LocaleService {
|
class MockLocaleService extends _i1.Mock implements _i30.LocaleService {
|
||||||
MockLocaleService() {
|
MockLocaleService() {
|
||||||
_i1.throwOnMissingStub(this);
|
_i1.throwOnMissingStub(this);
|
||||||
}
|
}
|
||||||
|
@ -2327,12 +2326,12 @@ class MockPrefs extends _i1.Mock implements _i23.Prefs {
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
_i30.SyncingType get syncType => (super.noSuchMethod(
|
_i31.SyncingType get syncType => (super.noSuchMethod(
|
||||||
Invocation.getter(#syncType),
|
Invocation.getter(#syncType),
|
||||||
returnValue: _i30.SyncingType.currentWalletOnly,
|
returnValue: _i31.SyncingType.currentWalletOnly,
|
||||||
) as _i30.SyncingType);
|
) as _i31.SyncingType);
|
||||||
@override
|
@override
|
||||||
set syncType(_i30.SyncingType? syncType) => super.noSuchMethod(
|
set syncType(_i31.SyncingType? syncType) => super.noSuchMethod(
|
||||||
Invocation.setter(
|
Invocation.setter(
|
||||||
#syncType,
|
#syncType,
|
||||||
syncType,
|
syncType,
|
||||||
|
@ -2465,12 +2464,12 @@ class MockPrefs extends _i1.Mock implements _i23.Prefs {
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
_i31.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
_i32.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
||||||
Invocation.getter(#backupFrequencyType),
|
Invocation.getter(#backupFrequencyType),
|
||||||
returnValue: _i31.BackupFrequencyType.everyTenMinutes,
|
returnValue: _i32.BackupFrequencyType.everyTenMinutes,
|
||||||
) as _i31.BackupFrequencyType);
|
) as _i32.BackupFrequencyType);
|
||||||
@override
|
@override
|
||||||
set backupFrequencyType(_i31.BackupFrequencyType? backupFrequencyType) =>
|
set backupFrequencyType(_i32.BackupFrequencyType? backupFrequencyType) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
Invocation.setter(
|
Invocation.setter(
|
||||||
#backupFrequencyType,
|
#backupFrequencyType,
|
||||||
|
|
|
@ -12,8 +12,9 @@ import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i5;
|
||||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i4;
|
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i4;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i6;
|
import 'package:stackwallet/models/balance.dart' as _i6;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i12;
|
||||||
import 'package:stackwallet/models/lelantus_coin.dart' as _i13;
|
import 'package:stackwallet/models/lelantus_coin.dart' as _i14;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i3;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i3;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i13;
|
||||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as _i9;
|
import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as _i9;
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||||
as _i2;
|
as _i2;
|
||||||
|
@ -485,7 +486,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i10.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i10.Future<List<_i13.SigningData>> fetchBuildTxData(
|
||||||
List<_i12.UTXO>? utxosToUse) =>
|
List<_i12.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -493,12 +494,11 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i10.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i10.Future<List<_i13.SigningData>>.value(<_i13.SigningData>[]),
|
||||||
) as _i10.Future<Map<String, dynamic>>);
|
) as _i10.Future<List<_i13.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i10.Future<Map<String, dynamic>> buildTransaction({
|
_i10.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i12.UTXO>? utxosToUse,
|
required List<_i13.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -507,7 +507,6 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -570,14 +569,14 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
||||||
returnValueForMissingStub: _i10.Future<void>.value(),
|
returnValueForMissingStub: _i10.Future<void>.value(),
|
||||||
) as _i10.Future<void>);
|
) as _i10.Future<void>);
|
||||||
@override
|
@override
|
||||||
List<Map<dynamic, _i13.LelantusCoin>> getLelantusCoinMap() =>
|
List<Map<dynamic, _i14.LelantusCoin>> getLelantusCoinMap() =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getLelantusCoinMap,
|
#getLelantusCoinMap,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
returnValue: <Map<dynamic, _i13.LelantusCoin>>[],
|
returnValue: <Map<dynamic, _i14.LelantusCoin>>[],
|
||||||
) as List<Map<dynamic, _i13.LelantusCoin>>);
|
) as List<Map<dynamic, _i14.LelantusCoin>>);
|
||||||
@override
|
@override
|
||||||
_i10.Future<void> anonymizeAllPublicFunds() => (super.noSuchMethod(
|
_i10.Future<void> anonymizeAllPublicFunds() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i22;
|
import 'dart:async' as _i22;
|
||||||
import 'dart:typed_data' as _i27;
|
import 'dart:typed_data' as _i28;
|
||||||
import 'dart:ui' as _i24;
|
import 'dart:ui' as _i24;
|
||||||
|
|
||||||
import 'package:bip32/bip32.dart' as _i16;
|
import 'package:bip32/bip32.dart' as _i16;
|
||||||
|
@ -18,12 +18,13 @@ import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i10;
|
||||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i11;
|
import 'package:stackwallet/models/balance.dart' as _i11;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
||||||
import 'package:stackwallet/models/node_model.dart' as _i29;
|
import 'package:stackwallet/models/node_model.dart' as _i30;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i27;
|
||||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25;
|
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25;
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
import 'package:stackwallet/services/locale_service.dart' as _i28;
|
import 'package:stackwallet/services/locale_service.dart' as _i29;
|
||||||
import 'package:stackwallet/services/node_service.dart' as _i3;
|
import 'package:stackwallet/services/node_service.dart' as _i3;
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||||
as _i7;
|
as _i7;
|
||||||
|
@ -1230,7 +1231,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i22.Future<List<_i27.SigningData>> fetchBuildTxData(
|
||||||
List<_i15.UTXO>? utxosToUse) =>
|
List<_i15.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -1238,12 +1239,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i22.Future<List<_i27.SigningData>>.value(<_i27.SigningData>[]),
|
||||||
) as _i22.Future<Map<String, dynamic>>);
|
) as _i22.Future<List<_i27.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i15.UTXO>? utxosToUse,
|
required List<_i27.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1252,7 +1252,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -1506,7 +1505,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
})?
|
})?
|
||||||
prepareSend,
|
prepareSend,
|
||||||
required _i22.Future<int> Function({required String address})? getTxCount,
|
required _i22.Future<int> Function({required String address})? getTxCount,
|
||||||
required _i22.Future<Map<String, dynamic>> Function(List<_i15.UTXO>)?
|
required _i22.Future<List<_i27.SigningData>> Function(List<_i15.UTXO>)?
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
required _i22.Future<void> Function()? refresh,
|
required _i22.Future<void> Function()? refresh,
|
||||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||||
|
@ -1658,14 +1657,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
)),
|
)),
|
||||||
) as _i22.Future<_i17.PaymentCode>);
|
) as _i22.Future<_i17.PaymentCode>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#signWithNotificationKey,
|
#signWithNotificationKey,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i22.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||||
) as _i22.Future<_i27.Uint8List>);
|
) as _i22.Future<_i28.Uint8List>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2001,7 +2000,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
/// A class which mocks [LocaleService].
|
/// A class which mocks [LocaleService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockLocaleService extends _i1.Mock implements _i28.LocaleService {
|
class MockLocaleService extends _i1.Mock implements _i29.LocaleService {
|
||||||
MockLocaleService() {
|
MockLocaleService() {
|
||||||
_i1.throwOnMissingStub(this);
|
_i1.throwOnMissingStub(this);
|
||||||
}
|
}
|
||||||
|
@ -2073,15 +2072,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
),
|
),
|
||||||
) as _i18.SecureStorageInterface);
|
) as _i18.SecureStorageInterface);
|
||||||
@override
|
@override
|
||||||
List<_i29.NodeModel> get primaryNodes => (super.noSuchMethod(
|
List<_i30.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||||
Invocation.getter(#primaryNodes),
|
Invocation.getter(#primaryNodes),
|
||||||
returnValue: <_i29.NodeModel>[],
|
returnValue: <_i30.NodeModel>[],
|
||||||
) as List<_i29.NodeModel>);
|
) as List<_i30.NodeModel>);
|
||||||
@override
|
@override
|
||||||
List<_i29.NodeModel> get nodes => (super.noSuchMethod(
|
List<_i30.NodeModel> get nodes => (super.noSuchMethod(
|
||||||
Invocation.getter(#nodes),
|
Invocation.getter(#nodes),
|
||||||
returnValue: <_i29.NodeModel>[],
|
returnValue: <_i30.NodeModel>[],
|
||||||
) as List<_i29.NodeModel>);
|
) as List<_i30.NodeModel>);
|
||||||
@override
|
@override
|
||||||
bool get hasListeners => (super.noSuchMethod(
|
bool get hasListeners => (super.noSuchMethod(
|
||||||
Invocation.getter(#hasListeners),
|
Invocation.getter(#hasListeners),
|
||||||
|
@ -2099,7 +2098,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> setPrimaryNodeFor({
|
_i22.Future<void> setPrimaryNodeFor({
|
||||||
required _i21.Coin? coin,
|
required _i21.Coin? coin,
|
||||||
required _i29.NodeModel? node,
|
required _i30.NodeModel? node,
|
||||||
bool? shouldNotifyListeners = false,
|
bool? shouldNotifyListeners = false,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2116,40 +2115,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
returnValueForMissingStub: _i22.Future<void>.value(),
|
returnValueForMissingStub: _i22.Future<void>.value(),
|
||||||
) as _i22.Future<void>);
|
) as _i22.Future<void>);
|
||||||
@override
|
@override
|
||||||
_i29.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
_i30.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||||
(super.noSuchMethod(Invocation.method(
|
(super.noSuchMethod(Invocation.method(
|
||||||
#getPrimaryNodeFor,
|
#getPrimaryNodeFor,
|
||||||
[],
|
[],
|
||||||
{#coin: coin},
|
{#coin: coin},
|
||||||
)) as _i29.NodeModel?);
|
)) as _i30.NodeModel?);
|
||||||
@override
|
@override
|
||||||
List<_i29.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
List<_i30.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getNodesFor,
|
#getNodesFor,
|
||||||
[coin],
|
[coin],
|
||||||
),
|
),
|
||||||
returnValue: <_i29.NodeModel>[],
|
returnValue: <_i30.NodeModel>[],
|
||||||
) as List<_i29.NodeModel>);
|
) as List<_i30.NodeModel>);
|
||||||
@override
|
@override
|
||||||
_i29.NodeModel? getNodeById({required String? id}) =>
|
_i30.NodeModel? getNodeById({required String? id}) =>
|
||||||
(super.noSuchMethod(Invocation.method(
|
(super.noSuchMethod(Invocation.method(
|
||||||
#getNodeById,
|
#getNodeById,
|
||||||
[],
|
[],
|
||||||
{#id: id},
|
{#id: id},
|
||||||
)) as _i29.NodeModel?);
|
)) as _i30.NodeModel?);
|
||||||
@override
|
@override
|
||||||
List<_i29.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
List<_i30.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#failoverNodesFor,
|
#failoverNodesFor,
|
||||||
[],
|
[],
|
||||||
{#coin: coin},
|
{#coin: coin},
|
||||||
),
|
),
|
||||||
returnValue: <_i29.NodeModel>[],
|
returnValue: <_i30.NodeModel>[],
|
||||||
) as List<_i29.NodeModel>);
|
) as List<_i30.NodeModel>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> add(
|
_i22.Future<void> add(
|
||||||
_i29.NodeModel? node,
|
_i30.NodeModel? node,
|
||||||
String? password,
|
String? password,
|
||||||
bool? shouldNotifyListeners,
|
bool? shouldNotifyListeners,
|
||||||
) =>
|
) =>
|
||||||
|
@ -2201,7 +2200,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
) as _i22.Future<void>);
|
) as _i22.Future<void>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> edit(
|
_i22.Future<void> edit(
|
||||||
_i29.NodeModel? editedNode,
|
_i30.NodeModel? editedNode,
|
||||||
String? password,
|
String? password,
|
||||||
bool? shouldNotifyListeners,
|
bool? shouldNotifyListeners,
|
||||||
) =>
|
) =>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i21;
|
import 'dart:async' as _i21;
|
||||||
import 'dart:typed_data' as _i27;
|
import 'dart:typed_data' as _i28;
|
||||||
import 'dart:ui' as _i23;
|
import 'dart:ui' as _i23;
|
||||||
|
|
||||||
import 'package:bip32/bip32.dart' as _i16;
|
import 'package:bip32/bip32.dart' as _i16;
|
||||||
|
@ -19,6 +19,7 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i11;
|
import 'package:stackwallet/models/balance.dart' as _i11;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i26;
|
||||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i24;
|
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i24;
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart' as _i18;
|
import 'package:stackwallet/services/coins/coin_service.dart' as _i18;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
|
@ -30,7 +31,7 @@ import 'package:stackwallet/services/wallets_service.dart' as _i2;
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i20;
|
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i20;
|
||||||
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i25;
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i25;
|
||||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
||||||
as _i26;
|
as _i27;
|
||||||
import 'package:stackwallet/utilities/prefs.dart' as _i22;
|
import 'package:stackwallet/utilities/prefs.dart' as _i22;
|
||||||
import 'package:tuple/tuple.dart' as _i14;
|
import 'package:tuple/tuple.dart' as _i14;
|
||||||
|
|
||||||
|
@ -1217,7 +1218,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i21.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i21.Future<List<_i26.SigningData>> fetchBuildTxData(
|
||||||
List<_i15.UTXO>? utxosToUse) =>
|
List<_i15.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -1225,12 +1226,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i21.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i21.Future<List<_i26.SigningData>>.value(<_i26.SigningData>[]),
|
||||||
) as _i21.Future<Map<String, dynamic>>);
|
) as _i21.Future<List<_i26.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i21.Future<Map<String, dynamic>> buildTransaction({
|
_i21.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i15.UTXO>? utxosToUse,
|
required List<_i26.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1239,7 +1239,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -1474,7 +1473,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
||||||
required _i20.Coin? coin,
|
required _i20.Coin? coin,
|
||||||
required _i12.MainDB? db,
|
required _i12.MainDB? db,
|
||||||
required _i9.ElectrumX? electrumXClient,
|
required _i9.ElectrumX? electrumXClient,
|
||||||
required _i26.SecureStorageInterface? secureStorage,
|
required _i27.SecureStorageInterface? secureStorage,
|
||||||
required int? dustLimitP2PKH,
|
required int? dustLimitP2PKH,
|
||||||
required int? minConfirms,
|
required int? minConfirms,
|
||||||
required _i21.Future<String?> Function()? getMnemonicString,
|
required _i21.Future<String?> Function()? getMnemonicString,
|
||||||
|
@ -1493,7 +1492,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
||||||
})?
|
})?
|
||||||
prepareSend,
|
prepareSend,
|
||||||
required _i21.Future<int> Function({required String address})? getTxCount,
|
required _i21.Future<int> Function({required String address})? getTxCount,
|
||||||
required _i21.Future<Map<String, dynamic>> Function(List<_i15.UTXO>)?
|
required _i21.Future<List<_i26.SigningData>> Function(List<_i15.UTXO>)?
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
required _i21.Future<void> Function()? refresh,
|
required _i21.Future<void> Function()? refresh,
|
||||||
required _i21.Future<void> Function()? checkChangeAddressForTransactions,
|
required _i21.Future<void> Function()? checkChangeAddressForTransactions,
|
||||||
|
@ -1645,14 +1644,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
||||||
)),
|
)),
|
||||||
) as _i21.Future<_i17.PaymentCode>);
|
) as _i21.Future<_i17.PaymentCode>);
|
||||||
@override
|
@override
|
||||||
_i21.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
_i21.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#signWithNotificationKey,
|
#signWithNotificationKey,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i21.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
returnValue: _i21.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||||
) as _i21.Future<_i27.Uint8List>);
|
) as _i21.Future<_i28.Uint8List>);
|
||||||
@override
|
@override
|
||||||
_i21.Future<String> signStringWithNotificationKey(String? data) =>
|
_i21.Future<String> signStringWithNotificationKey(String? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
|
|
@ -16,20 +16,21 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i11;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i9;
|
import 'package:stackwallet/models/balance.dart' as _i9;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i21;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i21;
|
||||||
import 'package:stackwallet/models/models.dart' as _i8;
|
import 'package:stackwallet/models/models.dart' as _i8;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i23;
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart' as _i7;
|
import 'package:stackwallet/services/coins/coin_service.dart' as _i7;
|
||||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as _i22;
|
import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as _i22;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
import 'package:stackwallet/services/locale_service.dart' as _i23;
|
import 'package:stackwallet/services/locale_service.dart' as _i24;
|
||||||
import 'package:stackwallet/services/node_service.dart' as _i3;
|
import 'package:stackwallet/services/node_service.dart' as _i3;
|
||||||
import 'package:stackwallet/services/notes_service.dart' as _i27;
|
import 'package:stackwallet/services/notes_service.dart' as _i28;
|
||||||
import 'package:stackwallet/services/price_service.dart' as _i26;
|
import 'package:stackwallet/services/price_service.dart' as _i27;
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||||
as _i10;
|
as _i10;
|
||||||
import 'package:stackwallet/services/wallets.dart' as _i16;
|
import 'package:stackwallet/services/wallets.dart' as _i16;
|
||||||
import 'package:stackwallet/services/wallets_service.dart' as _i2;
|
import 'package:stackwallet/services/wallets_service.dart' as _i2;
|
||||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i25;
|
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i26;
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i17;
|
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i17;
|
||||||
import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i24;
|
import 'package:stackwallet/utilities/enums/sync_type_enum.dart' as _i25;
|
||||||
import 'package:stackwallet/utilities/prefs.dart' as _i19;
|
import 'package:stackwallet/utilities/prefs.dart' as _i19;
|
||||||
import 'package:tuple/tuple.dart' as _i15;
|
import 'package:tuple/tuple.dart' as _i15;
|
||||||
|
|
||||||
|
@ -1443,7 +1444,7 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i18.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i18.Future<List<_i23.SigningData>> fetchBuildTxData(
|
||||||
List<_i21.UTXO>? utxosToUse) =>
|
List<_i21.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -1451,12 +1452,11 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i18.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i18.Future<List<_i23.SigningData>>.value(<_i23.SigningData>[]),
|
||||||
) as _i18.Future<Map<String, dynamic>>);
|
) as _i18.Future<List<_i23.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i18.Future<Map<String, dynamic>> buildTransaction({
|
_i18.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i21.UTXO>? utxosToUse,
|
required List<_i23.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1465,7 +1465,6 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -2001,7 +2000,7 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
||||||
/// A class which mocks [LocaleService].
|
/// A class which mocks [LocaleService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockLocaleService extends _i1.Mock implements _i23.LocaleService {
|
class MockLocaleService extends _i1.Mock implements _i24.LocaleService {
|
||||||
MockLocaleService() {
|
MockLocaleService() {
|
||||||
_i1.throwOnMissingStub(this);
|
_i1.throwOnMissingStub(this);
|
||||||
}
|
}
|
||||||
|
@ -2119,12 +2118,12 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
_i24.SyncingType get syncType => (super.noSuchMethod(
|
_i25.SyncingType get syncType => (super.noSuchMethod(
|
||||||
Invocation.getter(#syncType),
|
Invocation.getter(#syncType),
|
||||||
returnValue: _i24.SyncingType.currentWalletOnly,
|
returnValue: _i25.SyncingType.currentWalletOnly,
|
||||||
) as _i24.SyncingType);
|
) as _i25.SyncingType);
|
||||||
@override
|
@override
|
||||||
set syncType(_i24.SyncingType? syncType) => super.noSuchMethod(
|
set syncType(_i25.SyncingType? syncType) => super.noSuchMethod(
|
||||||
Invocation.setter(
|
Invocation.setter(
|
||||||
#syncType,
|
#syncType,
|
||||||
syncType,
|
syncType,
|
||||||
|
@ -2257,12 +2256,12 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
_i25.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
_i26.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
||||||
Invocation.getter(#backupFrequencyType),
|
Invocation.getter(#backupFrequencyType),
|
||||||
returnValue: _i25.BackupFrequencyType.everyTenMinutes,
|
returnValue: _i26.BackupFrequencyType.everyTenMinutes,
|
||||||
) as _i25.BackupFrequencyType);
|
) as _i26.BackupFrequencyType);
|
||||||
@override
|
@override
|
||||||
set backupFrequencyType(_i25.BackupFrequencyType? backupFrequencyType) =>
|
set backupFrequencyType(_i26.BackupFrequencyType? backupFrequencyType) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
Invocation.setter(
|
Invocation.setter(
|
||||||
#backupFrequencyType,
|
#backupFrequencyType,
|
||||||
|
@ -2425,7 +2424,7 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
|
||||||
/// A class which mocks [PriceService].
|
/// A class which mocks [PriceService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockPriceService extends _i1.Mock implements _i26.PriceService {
|
class MockPriceService extends _i1.Mock implements _i27.PriceService {
|
||||||
MockPriceService() {
|
MockPriceService() {
|
||||||
_i1.throwOnMissingStub(this);
|
_i1.throwOnMissingStub(this);
|
||||||
}
|
}
|
||||||
|
@ -2533,7 +2532,7 @@ class MockPriceService extends _i1.Mock implements _i26.PriceService {
|
||||||
/// A class which mocks [NotesService].
|
/// A class which mocks [NotesService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockNotesService extends _i1.Mock implements _i27.NotesService {
|
class MockNotesService extends _i1.Mock implements _i28.NotesService {
|
||||||
MockNotesService() {
|
MockNotesService() {
|
||||||
_i1.throwOnMissingStub(this);
|
_i1.throwOnMissingStub(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i20;
|
import 'dart:async' as _i20;
|
||||||
import 'dart:typed_data' as _i26;
|
import 'dart:typed_data' as _i27;
|
||||||
import 'dart:ui' as _i22;
|
import 'dart:ui' as _i22;
|
||||||
|
|
||||||
import 'package:bip32/bip32.dart' as _i16;
|
import 'package:bip32/bip32.dart' as _i16;
|
||||||
|
@ -19,9 +19,10 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i11;
|
import 'package:stackwallet/models/balance.dart' as _i11;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i25;
|
||||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i23;
|
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i23;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
import 'package:stackwallet/services/locale_service.dart' as _i27;
|
import 'package:stackwallet/services/locale_service.dart' as _i28;
|
||||||
import 'package:stackwallet/services/node_service.dart' as _i3;
|
import 'package:stackwallet/services/node_service.dart' as _i3;
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||||
as _i7;
|
as _i7;
|
||||||
|
@ -30,7 +31,7 @@ import 'package:stackwallet/services/wallets_service.dart' as _i2;
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i19;
|
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i19;
|
||||||
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i24;
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart' as _i24;
|
||||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
||||||
as _i25;
|
as _i26;
|
||||||
import 'package:stackwallet/utilities/prefs.dart' as _i21;
|
import 'package:stackwallet/utilities/prefs.dart' as _i21;
|
||||||
import 'package:tuple/tuple.dart' as _i14;
|
import 'package:tuple/tuple.dart' as _i14;
|
||||||
|
|
||||||
|
@ -980,7 +981,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i20.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i20.Future<List<_i25.SigningData>> fetchBuildTxData(
|
||||||
List<_i15.UTXO>? utxosToUse) =>
|
List<_i15.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -988,12 +989,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i20.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i20.Future<List<_i25.SigningData>>.value(<_i25.SigningData>[]),
|
||||||
) as _i20.Future<Map<String, dynamic>>);
|
) as _i20.Future<List<_i25.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i20.Future<Map<String, dynamic>> buildTransaction({
|
_i20.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i15.UTXO>? utxosToUse,
|
required List<_i25.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1002,7 +1002,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -1237,7 +1236,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
required _i19.Coin? coin,
|
required _i19.Coin? coin,
|
||||||
required _i12.MainDB? db,
|
required _i12.MainDB? db,
|
||||||
required _i9.ElectrumX? electrumXClient,
|
required _i9.ElectrumX? electrumXClient,
|
||||||
required _i25.SecureStorageInterface? secureStorage,
|
required _i26.SecureStorageInterface? secureStorage,
|
||||||
required int? dustLimitP2PKH,
|
required int? dustLimitP2PKH,
|
||||||
required int? minConfirms,
|
required int? minConfirms,
|
||||||
required _i20.Future<String?> Function()? getMnemonicString,
|
required _i20.Future<String?> Function()? getMnemonicString,
|
||||||
|
@ -1256,7 +1255,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
})?
|
})?
|
||||||
prepareSend,
|
prepareSend,
|
||||||
required _i20.Future<int> Function({required String address})? getTxCount,
|
required _i20.Future<int> Function({required String address})? getTxCount,
|
||||||
required _i20.Future<Map<String, dynamic>> Function(List<_i15.UTXO>)?
|
required _i20.Future<List<_i25.SigningData>> Function(List<_i15.UTXO>)?
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
required _i20.Future<void> Function()? refresh,
|
required _i20.Future<void> Function()? refresh,
|
||||||
required _i20.Future<void> Function()? checkChangeAddressForTransactions,
|
required _i20.Future<void> Function()? checkChangeAddressForTransactions,
|
||||||
|
@ -1408,14 +1407,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
)),
|
)),
|
||||||
) as _i20.Future<_i17.PaymentCode>);
|
) as _i20.Future<_i17.PaymentCode>);
|
||||||
@override
|
@override
|
||||||
_i20.Future<_i26.Uint8List> signWithNotificationKey(_i26.Uint8List? data) =>
|
_i20.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#signWithNotificationKey,
|
#signWithNotificationKey,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i20.Future<_i26.Uint8List>.value(_i26.Uint8List(0)),
|
returnValue: _i20.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
||||||
) as _i20.Future<_i26.Uint8List>);
|
) as _i20.Future<_i27.Uint8List>);
|
||||||
@override
|
@override
|
||||||
_i20.Future<String> signStringWithNotificationKey(String? data) =>
|
_i20.Future<String> signStringWithNotificationKey(String? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -1751,7 +1750,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
||||||
/// A class which mocks [LocaleService].
|
/// A class which mocks [LocaleService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockLocaleService extends _i1.Mock implements _i27.LocaleService {
|
class MockLocaleService extends _i1.Mock implements _i28.LocaleService {
|
||||||
MockLocaleService() {
|
MockLocaleService() {
|
||||||
_i1.throwOnMissingStub(this);
|
_i1.throwOnMissingStub(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i22;
|
import 'dart:async' as _i22;
|
||||||
import 'dart:typed_data' as _i27;
|
import 'dart:typed_data' as _i28;
|
||||||
import 'dart:ui' as _i24;
|
import 'dart:ui' as _i24;
|
||||||
|
|
||||||
import 'package:bip32/bip32.dart' as _i16;
|
import 'package:bip32/bip32.dart' as _i16;
|
||||||
|
@ -18,8 +18,9 @@ import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i10;
|
||||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i11;
|
import 'package:stackwallet/models/balance.dart' as _i11;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
||||||
import 'package:stackwallet/models/node_model.dart' as _i28;
|
import 'package:stackwallet/models/node_model.dart' as _i29;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i27;
|
||||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25;
|
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25;
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
|
@ -1229,7 +1230,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i22.Future<List<_i27.SigningData>> fetchBuildTxData(
|
||||||
List<_i15.UTXO>? utxosToUse) =>
|
List<_i15.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -1237,12 +1238,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i22.Future<List<_i27.SigningData>>.value(<_i27.SigningData>[]),
|
||||||
) as _i22.Future<Map<String, dynamic>>);
|
) as _i22.Future<List<_i27.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i15.UTXO>? utxosToUse,
|
required List<_i27.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1251,7 +1251,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -1505,7 +1504,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
})?
|
})?
|
||||||
prepareSend,
|
prepareSend,
|
||||||
required _i22.Future<int> Function({required String address})? getTxCount,
|
required _i22.Future<int> Function({required String address})? getTxCount,
|
||||||
required _i22.Future<Map<String, dynamic>> Function(List<_i15.UTXO>)?
|
required _i22.Future<List<_i27.SigningData>> Function(List<_i15.UTXO>)?
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
required _i22.Future<void> Function()? refresh,
|
required _i22.Future<void> Function()? refresh,
|
||||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||||
|
@ -1657,14 +1656,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
)),
|
)),
|
||||||
) as _i22.Future<_i17.PaymentCode>);
|
) as _i22.Future<_i17.PaymentCode>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#signWithNotificationKey,
|
#signWithNotificationKey,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i22.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||||
) as _i22.Future<_i27.Uint8List>);
|
) as _i22.Future<_i28.Uint8List>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2010,15 +2009,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
),
|
),
|
||||||
) as _i18.SecureStorageInterface);
|
) as _i18.SecureStorageInterface);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> get primaryNodes => (super.noSuchMethod(
|
List<_i29.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||||
Invocation.getter(#primaryNodes),
|
Invocation.getter(#primaryNodes),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> get nodes => (super.noSuchMethod(
|
List<_i29.NodeModel> get nodes => (super.noSuchMethod(
|
||||||
Invocation.getter(#nodes),
|
Invocation.getter(#nodes),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
bool get hasListeners => (super.noSuchMethod(
|
bool get hasListeners => (super.noSuchMethod(
|
||||||
Invocation.getter(#hasListeners),
|
Invocation.getter(#hasListeners),
|
||||||
|
@ -2036,7 +2035,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> setPrimaryNodeFor({
|
_i22.Future<void> setPrimaryNodeFor({
|
||||||
required _i21.Coin? coin,
|
required _i21.Coin? coin,
|
||||||
required _i28.NodeModel? node,
|
required _i29.NodeModel? node,
|
||||||
bool? shouldNotifyListeners = false,
|
bool? shouldNotifyListeners = false,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2053,40 +2052,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
returnValueForMissingStub: _i22.Future<void>.value(),
|
returnValueForMissingStub: _i22.Future<void>.value(),
|
||||||
) as _i22.Future<void>);
|
) as _i22.Future<void>);
|
||||||
@override
|
@override
|
||||||
_i28.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
_i29.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||||
(super.noSuchMethod(Invocation.method(
|
(super.noSuchMethod(Invocation.method(
|
||||||
#getPrimaryNodeFor,
|
#getPrimaryNodeFor,
|
||||||
[],
|
[],
|
||||||
{#coin: coin},
|
{#coin: coin},
|
||||||
)) as _i28.NodeModel?);
|
)) as _i29.NodeModel?);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
List<_i29.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getNodesFor,
|
#getNodesFor,
|
||||||
[coin],
|
[coin],
|
||||||
),
|
),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
_i28.NodeModel? getNodeById({required String? id}) =>
|
_i29.NodeModel? getNodeById({required String? id}) =>
|
||||||
(super.noSuchMethod(Invocation.method(
|
(super.noSuchMethod(Invocation.method(
|
||||||
#getNodeById,
|
#getNodeById,
|
||||||
[],
|
[],
|
||||||
{#id: id},
|
{#id: id},
|
||||||
)) as _i28.NodeModel?);
|
)) as _i29.NodeModel?);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
List<_i29.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#failoverNodesFor,
|
#failoverNodesFor,
|
||||||
[],
|
[],
|
||||||
{#coin: coin},
|
{#coin: coin},
|
||||||
),
|
),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> add(
|
_i22.Future<void> add(
|
||||||
_i28.NodeModel? node,
|
_i29.NodeModel? node,
|
||||||
String? password,
|
String? password,
|
||||||
bool? shouldNotifyListeners,
|
bool? shouldNotifyListeners,
|
||||||
) =>
|
) =>
|
||||||
|
@ -2138,7 +2137,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
) as _i22.Future<void>);
|
) as _i22.Future<void>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> edit(
|
_i22.Future<void> edit(
|
||||||
_i28.NodeModel? editedNode,
|
_i29.NodeModel? editedNode,
|
||||||
String? password,
|
String? password,
|
||||||
bool? shouldNotifyListeners,
|
bool? shouldNotifyListeners,
|
||||||
) =>
|
) =>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i22;
|
import 'dart:async' as _i22;
|
||||||
import 'dart:typed_data' as _i27;
|
import 'dart:typed_data' as _i28;
|
||||||
import 'dart:ui' as _i24;
|
import 'dart:ui' as _i24;
|
||||||
|
|
||||||
import 'package:bip32/bip32.dart' as _i16;
|
import 'package:bip32/bip32.dart' as _i16;
|
||||||
|
@ -18,8 +18,9 @@ import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i10;
|
||||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i9;
|
||||||
import 'package:stackwallet/models/balance.dart' as _i11;
|
import 'package:stackwallet/models/balance.dart' as _i11;
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
import 'package:stackwallet/models/isar/models/isar_models.dart' as _i15;
|
||||||
import 'package:stackwallet/models/node_model.dart' as _i28;
|
import 'package:stackwallet/models/node_model.dart' as _i29;
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
import 'package:stackwallet/models/paymint/fee_object_model.dart' as _i8;
|
||||||
|
import 'package:stackwallet/models/signing_data.dart' as _i27;
|
||||||
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25;
|
import 'package:stackwallet/services/coins/bitcoin/bitcoin_wallet.dart' as _i25;
|
||||||
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
import 'package:stackwallet/services/coins/coin_service.dart' as _i19;
|
||||||
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
import 'package:stackwallet/services/coins/manager.dart' as _i6;
|
||||||
|
@ -1229,7 +1230,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
_i22.Future<List<_i27.SigningData>> fetchBuildTxData(
|
||||||
List<_i15.UTXO>? utxosToUse) =>
|
List<_i15.UTXO>? utxosToUse) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
@ -1237,12 +1238,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
[utxosToUse],
|
[utxosToUse],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i22.Future<List<_i27.SigningData>>.value(<_i27.SigningData>[]),
|
||||||
) as _i22.Future<Map<String, dynamic>>);
|
) as _i22.Future<List<_i27.SigningData>>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||||
required List<_i15.UTXO>? utxosToUse,
|
required List<_i27.SigningData>? utxoSigningData,
|
||||||
required Map<String, dynamic>? utxoSigningData,
|
|
||||||
required List<String>? recipients,
|
required List<String>? recipients,
|
||||||
required List<int>? satoshiAmounts,
|
required List<int>? satoshiAmounts,
|
||||||
}) =>
|
}) =>
|
||||||
|
@ -1251,7 +1251,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
#buildTransaction,
|
#buildTransaction,
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
#utxosToUse: utxosToUse,
|
|
||||||
#utxoSigningData: utxoSigningData,
|
#utxoSigningData: utxoSigningData,
|
||||||
#recipients: recipients,
|
#recipients: recipients,
|
||||||
#satoshiAmounts: satoshiAmounts,
|
#satoshiAmounts: satoshiAmounts,
|
||||||
|
@ -1505,7 +1504,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
})?
|
})?
|
||||||
prepareSend,
|
prepareSend,
|
||||||
required _i22.Future<int> Function({required String address})? getTxCount,
|
required _i22.Future<int> Function({required String address})? getTxCount,
|
||||||
required _i22.Future<Map<String, dynamic>> Function(List<_i15.UTXO>)?
|
required _i22.Future<List<_i27.SigningData>> Function(List<_i15.UTXO>)?
|
||||||
fetchBuildTxData,
|
fetchBuildTxData,
|
||||||
required _i22.Future<void> Function()? refresh,
|
required _i22.Future<void> Function()? refresh,
|
||||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||||
|
@ -1657,14 +1656,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
||||||
)),
|
)),
|
||||||
) as _i22.Future<_i17.PaymentCode>);
|
) as _i22.Future<_i17.PaymentCode>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#signWithNotificationKey,
|
#signWithNotificationKey,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i22.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||||
) as _i22.Future<_i27.Uint8List>);
|
) as _i22.Future<_i28.Uint8List>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2010,15 +2009,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
),
|
),
|
||||||
) as _i18.SecureStorageInterface);
|
) as _i18.SecureStorageInterface);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> get primaryNodes => (super.noSuchMethod(
|
List<_i29.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||||
Invocation.getter(#primaryNodes),
|
Invocation.getter(#primaryNodes),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> get nodes => (super.noSuchMethod(
|
List<_i29.NodeModel> get nodes => (super.noSuchMethod(
|
||||||
Invocation.getter(#nodes),
|
Invocation.getter(#nodes),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
bool get hasListeners => (super.noSuchMethod(
|
bool get hasListeners => (super.noSuchMethod(
|
||||||
Invocation.getter(#hasListeners),
|
Invocation.getter(#hasListeners),
|
||||||
|
@ -2036,7 +2035,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> setPrimaryNodeFor({
|
_i22.Future<void> setPrimaryNodeFor({
|
||||||
required _i21.Coin? coin,
|
required _i21.Coin? coin,
|
||||||
required _i28.NodeModel? node,
|
required _i29.NodeModel? node,
|
||||||
bool? shouldNotifyListeners = false,
|
bool? shouldNotifyListeners = false,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
@ -2053,40 +2052,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
returnValueForMissingStub: _i22.Future<void>.value(),
|
returnValueForMissingStub: _i22.Future<void>.value(),
|
||||||
) as _i22.Future<void>);
|
) as _i22.Future<void>);
|
||||||
@override
|
@override
|
||||||
_i28.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
_i29.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||||
(super.noSuchMethod(Invocation.method(
|
(super.noSuchMethod(Invocation.method(
|
||||||
#getPrimaryNodeFor,
|
#getPrimaryNodeFor,
|
||||||
[],
|
[],
|
||||||
{#coin: coin},
|
{#coin: coin},
|
||||||
)) as _i28.NodeModel?);
|
)) as _i29.NodeModel?);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
List<_i29.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getNodesFor,
|
#getNodesFor,
|
||||||
[coin],
|
[coin],
|
||||||
),
|
),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
_i28.NodeModel? getNodeById({required String? id}) =>
|
_i29.NodeModel? getNodeById({required String? id}) =>
|
||||||
(super.noSuchMethod(Invocation.method(
|
(super.noSuchMethod(Invocation.method(
|
||||||
#getNodeById,
|
#getNodeById,
|
||||||
[],
|
[],
|
||||||
{#id: id},
|
{#id: id},
|
||||||
)) as _i28.NodeModel?);
|
)) as _i29.NodeModel?);
|
||||||
@override
|
@override
|
||||||
List<_i28.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
List<_i29.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#failoverNodesFor,
|
#failoverNodesFor,
|
||||||
[],
|
[],
|
||||||
{#coin: coin},
|
{#coin: coin},
|
||||||
),
|
),
|
||||||
returnValue: <_i28.NodeModel>[],
|
returnValue: <_i29.NodeModel>[],
|
||||||
) as List<_i28.NodeModel>);
|
) as List<_i29.NodeModel>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> add(
|
_i22.Future<void> add(
|
||||||
_i28.NodeModel? node,
|
_i29.NodeModel? node,
|
||||||
String? password,
|
String? password,
|
||||||
bool? shouldNotifyListeners,
|
bool? shouldNotifyListeners,
|
||||||
) =>
|
) =>
|
||||||
|
@ -2138,7 +2137,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||||
) as _i22.Future<void>);
|
) as _i22.Future<void>);
|
||||||
@override
|
@override
|
||||||
_i22.Future<void> edit(
|
_i22.Future<void> edit(
|
||||||
_i28.NodeModel? editedNode,
|
_i29.NodeModel? editedNode,
|
||||||
String? password,
|
String? password,
|
||||||
bool? shouldNotifyListeners,
|
bool? shouldNotifyListeners,
|
||||||
) =>
|
) =>
|
||||||
|
|
Loading…
Reference in a new issue