mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-28 01:58:46 +00:00
commit
57e1818586
25 changed files with 1243 additions and 2262 deletions
README.md
ios
lib
models
pages/send_view
services
widgets
scripts
test
pages/send_view
services/coins
widget_tests
|
@ -22,10 +22,10 @@ Highlights include:
|
|||
- The only OS supported for building is Ubuntu 20.04
|
||||
- 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)
|
||||
- Dart SDK Requirement (>=2.17.0, up until <3.0.0)
|
||||
- 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.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)
|
||||
|
||||
### Scripted setup
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>10.0</string>
|
||||
<string>15.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# 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.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
|
|
@ -439,7 +439,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
|
@ -574,7 +574,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
|
@ -624,7 +624,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = 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);
|
||||
|
||||
// if (_amountToSend == null) {
|
||||
// setState(() {
|
||||
// _calculateFeesFuture = calculateFees(0);
|
||||
// });
|
||||
// } else {
|
||||
// setState(() {
|
||||
// _calculateFeesFuture =
|
||||
// calculateFees(Format.decimalAmountToSatoshis(_amountToSend!));
|
||||
// });
|
||||
// }
|
||||
_cryptoAmountChangedFeeUpdateTimer?.cancel();
|
||||
_cryptoAmountChangedFeeUpdateTimer = Timer(updateFeesTimerDuration, () {
|
||||
if (coin != Coin.epicCash && !_baseFocus.hasFocus) {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
_amountToSend == null
|
||||
? 0
|
||||
: 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)) {
|
||||
// confirm send all
|
||||
if (amount == availableBalance) {
|
||||
final bool? shouldSendAll = await showDialog<bool>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return StackDialog(
|
||||
title: "Confirm send all",
|
||||
message:
|
||||
"You are about to send your entire balance. Would you like to continue?",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonStyle(context),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
bool? shouldSendAll;
|
||||
if (mounted) {
|
||||
shouldSendAll = await showDialog<bool>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return StackDialog(
|
||||
title: "Confirm send all",
|
||||
message:
|
||||
"You are about to send your entire balance. Would you like to continue?",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonStyle(context),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonStyle(context),
|
||||
child: Text(
|
||||
"Yes",
|
||||
style: STextStyles.button(context),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonStyle(context),
|
||||
child: Text(
|
||||
"Yes",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (shouldSendAll == null || shouldSendAll == false) {
|
||||
// cancel preview
|
||||
|
@ -378,22 +423,24 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
try {
|
||||
bool wasCancelled = false;
|
||||
|
||||
unawaited(
|
||||
showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return BuildingTransactionDialog(
|
||||
onCancel: () {
|
||||
wasCancelled = true;
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return BuildingTransactionDialog(
|
||||
onCancel: () {
|
||||
wasCancelled = true;
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> txData;
|
||||
|
||||
|
@ -519,6 +566,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
|
||||
onCryptoAmountChanged = _cryptoAmountChanged;
|
||||
cryptoAmountController.addListener(onCryptoAmountChanged);
|
||||
baseAmountController.addListener(_baseAmountChanged);
|
||||
|
||||
if (_data != null) {
|
||||
if (_data!.amount != null) {
|
||||
|
@ -534,43 +582,47 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
noteController.text = "PayNym send";
|
||||
}
|
||||
|
||||
if (coin != Coin.epicCash) {
|
||||
_cryptoFocus.addListener(() {
|
||||
if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
||||
if (_amountToSend == null) {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(0);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// if (coin != Coin.epicCash) {
|
||||
// _cryptoFocus.addListener(() {
|
||||
// if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
||||
// if (_amountToSend == null) {
|
||||
// setState(() {
|
||||
// _calculateFeesFuture = calculateFees(0);
|
||||
// });
|
||||
// } else {
|
||||
// setState(() {
|
||||
// _calculateFeesFuture = calculateFees(
|
||||
// Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
_baseFocus.addListener(() {
|
||||
if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
||||
if (_amountToSend == null) {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(0);
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
_calculateFeesFuture = calculateFees(
|
||||
Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// _baseFocus.addListener(() {
|
||||
// if (!_cryptoFocus.hasFocus && !_baseFocus.hasFocus) {
|
||||
// if (_amountToSend == null) {
|
||||
// setState(() {
|
||||
// _calculateFeesFuture = calculateFees(0);
|
||||
// });
|
||||
// } else {
|
||||
// setState(() {
|
||||
// _calculateFeesFuture = calculateFees(
|
||||
// Format.decimalAmountToSatoshis(_amountToSend!, coin));
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cryptoAmountChangedFeeUpdateTimer?.cancel();
|
||||
_baseAmountChangedFeeUpdateTimer?.cancel();
|
||||
|
||||
cryptoAmountController.removeListener(onCryptoAmountChanged);
|
||||
baseAmountController.removeListener(_baseAmountChanged);
|
||||
|
||||
sendToController.dispose();
|
||||
cryptoAmountController.dispose();
|
||||
|
@ -1569,26 +1621,52 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
? "Select coins"
|
||||
: "Selected coins (${selectedUTXOs.length})",
|
||||
onTap: () async {
|
||||
final result =
|
||||
await Navigator.of(context).pushNamed(
|
||||
CoinControlView.routeName,
|
||||
arguments: Tuple4(
|
||||
walletId,
|
||||
CoinControlViewType.use,
|
||||
_amountToSend != null
|
||||
? Format.decimalAmountToSatoshis(
|
||||
_amountToSend!,
|
||||
coin,
|
||||
)
|
||||
: null,
|
||||
selectedUTXOs,
|
||||
),
|
||||
);
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
);
|
||||
}
|
||||
|
||||
if (result is Set<UTXO>) {
|
||||
setState(() {
|
||||
selectedUTXOs = result;
|
||||
});
|
||||
if (mounted) {
|
||||
final spendable = ref
|
||||
.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) ??
|
||||
Decimal.zero,
|
||||
updateChosen: (String fee) {
|
||||
_setCurrentFee(
|
||||
fee,
|
||||
true,
|
||||
);
|
||||
setState(() {
|
||||
_calculateFeesFuture =
|
||||
Future(() => fee);
|
||||
|
@ -1736,6 +1818,10 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
ConnectionState
|
||||
.done &&
|
||||
snapshot.hasData) {
|
||||
_setCurrentFee(
|
||||
snapshot.data! as String,
|
||||
false,
|
||||
);
|
||||
return Text(
|
||||
"~${snapshot.data! as String} ${coin.ticker}",
|
||||
style: STextStyles
|
||||
|
@ -1788,6 +1874,11 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
ConnectionState
|
||||
.done &&
|
||||
snapshot.hasData) {
|
||||
_setCurrentFee(
|
||||
snapshot.data!
|
||||
as String,
|
||||
false,
|
||||
);
|
||||
return Text(
|
||||
"~${snapshot.data! as String} ${coin.ticker}",
|
||||
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/isar/models/isar_models.dart' as isar_models;
|
||||
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/event_bus/events/global/node_connection_status_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;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: utxos is List<isar_models.UTXO>,
|
||||
coinControl: coinControl,
|
||||
);
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -1841,14 +1844,16 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
String? blockReason;
|
||||
|
||||
if (storedTx?.subType ==
|
||||
isar_models.TransactionSubType.bip47Notification &&
|
||||
storedTx?.type == isar_models.TransactionType.incoming) {
|
||||
// probably safe to assume this is an incoming tx as it is a utxo
|
||||
// belonging to this wallet. The extra check may be redundant but
|
||||
// just in case...
|
||||
|
||||
shouldBlock = true;
|
||||
blockReason = "Incoming paynym notification transaction.";
|
||||
isar_models.TransactionSubType.bip47Notification) {
|
||||
if (storedTx?.type == isar_models.TransactionType.incoming) {
|
||||
shouldBlock = true;
|
||||
blockReason = "Incoming paynym notification transaction.";
|
||||
} else if (storedTx?.type == isar_models.TransactionType.outgoing) {
|
||||
shouldBlock = true;
|
||||
blockReason = "Paynym notification change output. Incautious "
|
||||
"handling of change outputs from notification transactions "
|
||||
"may cause unintended loss of privacy.";
|
||||
}
|
||||
}
|
||||
|
||||
final vout = jsonUTXO["tx_pos"] as int;
|
||||
|
@ -2360,6 +2365,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
} else {
|
||||
satoshisBeingUsed = spendableSatoshiValue;
|
||||
utxoObjectsToUse = spendableOutputs;
|
||||
inputsBeingConsumed = spendableOutputs.length;
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
|
@ -2381,7 +2387,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -2399,7 +2404,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: [amount],
|
||||
|
@ -2410,7 +2414,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": amount,
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2418,7 +2422,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
final int vSizeForOneOutput;
|
||||
try {
|
||||
vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -2431,7 +2434,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
final int vSizeForTwoOutPuts;
|
||||
try {
|
||||
vSizeForTwoOutPuts = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [
|
||||
recipientAddress,
|
||||
|
@ -2502,7 +2504,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2530,7 +2531,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||
level: LogLevel.Info);
|
||||
txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2543,7 +2543,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2560,7 +2560,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2571,7 +2570,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2590,7 +2589,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2601,7 +2599,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2620,7 +2618,6 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2631,7 +2628,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2657,241 +2654,144 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
Future<List<SigningData>> fetchBuildTxData(
|
||||
List<isar_models.UTXO> utxosToUse,
|
||||
) async {
|
||||
// return data
|
||||
Map<String, dynamic> results = {};
|
||||
Map<String, List<String>> addressTxid = {};
|
||||
|
||||
// addresses to check
|
||||
List<String> addressesP2PKH = [];
|
||||
List<String> addressesP2SH = [];
|
||||
List<String> addressesP2WPKH = [];
|
||||
List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
txHash: txid,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
for (final output in tx["vout"] as List) {
|
||||
final n = output["n"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = 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");
|
||||
if (utxosToUse[i].address == null) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||
|
||||
signingData.add(
|
||||
SigningData(
|
||||
derivePathType: derivePathType,
|
||||
utxo: utxosToUse[i],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// p2pkh / bip44
|
||||
final p2pkhLength = addressesP2PKH.length;
|
||||
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;
|
||||
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[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[addressesP2PKH[i]];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
for (final sd in signingData) {
|
||||
String? pubKey;
|
||||
String? wif;
|
||||
|
||||
// fetch receiving derivations if null
|
||||
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||
chain: 0,
|
||||
derivePathType: sd.derivePathType,
|
||||
);
|
||||
final receiveDerivation =
|
||||
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||
|
||||
if (receiveDerivation != null) {
|
||||
pubKey = receiveDerivation["pubKey"] as String;
|
||||
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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
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) {
|
||||
case DerivePathType.bip49:
|
||||
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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = p2wpkh.output;
|
||||
data = P2SH(
|
||||
data: PaymentData(redeem: p2wpkh),
|
||||
network: _network,
|
||||
).data;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: _network,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
case DerivePathType.bip84:
|
||||
data = P2WPKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
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) {
|
||||
Logging.instance
|
||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||
|
@ -2901,8 +2801,7 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
|
||||
/// Builds and signs a transaction
|
||||
Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<isar_models.UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
|
@ -2913,10 +2812,14 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
txb.setVersion(1);
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List);
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
|
@ -2926,13 +2829,12 @@ class BitcoinWallet extends CoinServiceAPI
|
|||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||
keyPair: utxoSigningData[i].keyPair!,
|
||||
witnessValue: utxoSigningData[i].utxo.value,
|
||||
redeemScript: utxoSigningData[i].redeemScript,
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
|
|
|
@ -1081,13 +1081,15 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final result = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: utxos is List<isar_models.UTXO>,
|
||||
coinControl: coinControl,
|
||||
);
|
||||
|
||||
Logging.instance
|
||||
|
@ -2426,6 +2428,7 @@ class BitcoinCashWallet extends CoinServiceAPI
|
|||
} else {
|
||||
satoshisBeingUsed = spendableSatoshiValue;
|
||||
utxoObjectsToUse = spendableOutputs;
|
||||
inputsBeingConsumed = spendableOutputs.length;
|
||||
}
|
||||
|
||||
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/isar/models/isar_models.dart' as isar_models;
|
||||
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/event_bus/events/global/node_connection_status_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;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final result = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: utxos is List<isar_models.UTXO>,
|
||||
coinControl: coinControl,
|
||||
);
|
||||
|
||||
Logging.instance
|
||||
|
@ -1586,14 +1589,16 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
String? blockReason;
|
||||
|
||||
if (storedTx?.subType ==
|
||||
isar_models.TransactionSubType.bip47Notification &&
|
||||
storedTx?.type == isar_models.TransactionType.incoming) {
|
||||
// probably safe to assume this is an incoming tx as it is a utxo
|
||||
// belonging to this wallet. The extra check may be redundant but
|
||||
// just in case...
|
||||
|
||||
shouldBlock = true;
|
||||
blockReason = "Incoming paynym notification transaction.";
|
||||
isar_models.TransactionSubType.bip47Notification) {
|
||||
if (storedTx?.type == isar_models.TransactionType.incoming) {
|
||||
shouldBlock = true;
|
||||
blockReason = "Incoming paynym notification transaction.";
|
||||
} else if (storedTx?.type == isar_models.TransactionType.outgoing) {
|
||||
shouldBlock = true;
|
||||
blockReason = "Paynym notification change output. Incautious "
|
||||
"handling of change outputs from notification transactions "
|
||||
"may cause unintended loss of privacy.";
|
||||
}
|
||||
}
|
||||
|
||||
final vout = jsonUTXO["tx_pos"] as int;
|
||||
|
@ -2126,6 +2131,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
} else {
|
||||
satoshisBeingUsed = spendableSatoshiValue;
|
||||
utxoObjectsToUse = spendableOutputs;
|
||||
inputsBeingConsumed = spendableOutputs.length;
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
|
@ -2149,7 +2155,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -2164,7 +2169,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: [amount],
|
||||
|
@ -2175,19 +2179,17 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": amount,
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
))["vSize"] as int;
|
||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [
|
||||
recipientAddress,
|
||||
|
@ -2267,7 +2269,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2295,7 +2296,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||
level: LogLevel.Info);
|
||||
txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2308,7 +2308,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2325,7 +2325,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2336,7 +2335,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2355,7 +2354,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2366,7 +2364,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2385,7 +2383,6 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2396,7 +2393,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2422,103 +2419,120 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
Future<List<SigningData>> fetchBuildTxData(
|
||||
List<isar_models.UTXO> utxosToUse,
|
||||
) async {
|
||||
// return data
|
||||
Map<String, dynamic> results = {};
|
||||
Map<String, List<String>> addressTxid = {};
|
||||
|
||||
// addresses to check
|
||||
List<String> addressesP2PKH = [];
|
||||
List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
txHash: txid,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
for (final output in tx["vout"] as List) {
|
||||
final n = output["n"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = output["scriptPubKey"]["addresses"][0] 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;
|
||||
default:
|
||||
throw Exception("Unsupported DerivePathType");
|
||||
if (utxosToUse[i].address == null) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||
|
||||
signingData.add(
|
||||
SigningData(
|
||||
derivePathType: derivePathType,
|
||||
utxo: utxosToUse[i],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// p2pkh / bip44
|
||||
final p2pkhLength = addressesP2PKH.length;
|
||||
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;
|
||||
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[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[addressesP2PKH[i]];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
for (final sd in signingData) {
|
||||
String? pubKey;
|
||||
String? wif;
|
||||
|
||||
// fetch receiving derivations if null
|
||||
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||
chain: 0,
|
||||
derivePathType: sd.derivePathType,
|
||||
);
|
||||
final receiveDerivation =
|
||||
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||
|
||||
if (receiveDerivation != null) {
|
||||
pubKey = receiveDerivation["pubKey"] as String;
|
||||
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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: network,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
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) {
|
||||
Logging.instance
|
||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||
|
@ -2528,8 +2542,7 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
|
||||
/// Builds and signs a transaction
|
||||
Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<isar_models.UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
|
@ -2540,10 +2553,14 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
txb.setVersion(1);
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List);
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
|
@ -2553,13 +2570,12 @@ class DogecoinWallet extends CoinServiceAPI
|
|||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||
keyPair: utxoSigningData[i].keyPair!,
|
||||
witnessValue: utxoSigningData[i].utxo.value,
|
||||
redeemScript: utxoSigningData[i].redeemScript,
|
||||
);
|
||||
}
|
||||
} 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_fee_data.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/event_bus/events/global/node_connection_status_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/default_nodes.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/flutter_secure_storage_interface.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);
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [_recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -1383,7 +1384,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: [amount],
|
||||
|
@ -1399,13 +1399,11 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
}
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [_recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
))["vSize"] as int;
|
||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [
|
||||
_recipientAddress,
|
||||
|
@ -1484,7 +1482,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -1512,7 +1509,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||
level: LogLevel.Info);
|
||||
txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -1541,7 +1537,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -1570,7 +1565,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -1599,7 +1593,6 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
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,
|
||||
) async {
|
||||
// return data
|
||||
Map<String, dynamic> results = {};
|
||||
Map<String, List<String>> addressTxid = {};
|
||||
|
||||
// addresses to check
|
||||
List<String> addresses = [];
|
||||
List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
txHash: txid,
|
||||
coin: coin,
|
||||
if (utxosToUse[i].address == null) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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) {
|
||||
final n = output["n"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = output["scriptPubKey"]["addresses"][0] as String;
|
||||
|
||||
if (!addressTxid.containsKey(address)) {
|
||||
addressTxid[address] = <String>[];
|
||||
}
|
||||
(addressTxid[address] as List).add(txid);
|
||||
|
||||
addresses.add(address);
|
||||
dynamic receiveDerivation;
|
||||
for (int j = 0;
|
||||
j < receiveDerivations[sd.derivePathType]!.length &&
|
||||
receiveDerivation == null;
|
||||
j++) {
|
||||
if (receiveDerivations[sd.derivePathType]!["$j"]["address"] ==
|
||||
sd.utxo.address!) {
|
||||
receiveDerivation = receiveDerivations[sd.derivePathType]!["$j"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// p2pkh / bip44
|
||||
final addressesLength = addresses.length;
|
||||
if (addressesLength > 0) {
|
||||
final receiveDerivationsString =
|
||||
await _secureStore.read(key: "${walletId}_receiveDerivations");
|
||||
final receiveDerivations = Map<String, dynamic>.from(
|
||||
jsonDecode(receiveDerivationsString ?? "{}") as Map);
|
||||
if (receiveDerivation != null) {
|
||||
pubKey = receiveDerivation["publicKey"] as String;
|
||||
wif = receiveDerivation["wif"] as String;
|
||||
} else {
|
||||
// fetch change derivations if null
|
||||
changeDerivations[sd.derivePathType] ??= Map<String, dynamic>.from(
|
||||
jsonDecode((await _secureStore.read(
|
||||
key: "${walletId}_changeDerivations",
|
||||
)) ??
|
||||
"{}") as Map,
|
||||
);
|
||||
|
||||
final changeDerivationsString =
|
||||
await _secureStore.read(key: "${walletId}_changeDerivations");
|
||||
final changeDerivations = Map<String, dynamic>.from(
|
||||
jsonDecode(changeDerivationsString ?? "{}") as Map);
|
||||
|
||||
for (int i = 0; i < addressesLength; i++) {
|
||||
// receives
|
||||
|
||||
dynamic receiveDerivation;
|
||||
|
||||
for (int j = 0; j < receiveDerivations.length; j++) {
|
||||
if (receiveDerivations["$j"]["address"] == addresses[i]) {
|
||||
receiveDerivation = receiveDerivations["$j"];
|
||||
dynamic changeDerivation;
|
||||
for (int j = 0;
|
||||
j < changeDerivations[sd.derivePathType]!.length &&
|
||||
changeDerivation == null;
|
||||
j++) {
|
||||
if (changeDerivations[sd.derivePathType]!["$j"]["address"] ==
|
||||
sd.utxo.address!) {
|
||||
changeDerivation = changeDerivations[sd.derivePathType]!["$j"];
|
||||
}
|
||||
}
|
||||
|
||||
// receiveDerivation = receiveDerivations[addresses[i]];
|
||||
// if a match exists it will not be null
|
||||
if (receiveDerivation != null) {
|
||||
final data = P2PKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
receiveDerivation["publicKey"] as String)),
|
||||
network: _network,
|
||||
).data;
|
||||
if (changeDerivation != null) {
|
||||
pubKey = changeDerivation["publicKey"] as String;
|
||||
wif = changeDerivation["wif"] as String;
|
||||
}
|
||||
}
|
||||
|
||||
for (String tx in addressTxid[addresses[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
receiveDerivation["wif"] as String,
|
||||
network: _network,
|
||||
),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// if its not a receive, check change
|
||||
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,
|
||||
);
|
||||
|
||||
dynamic changeDerivation;
|
||||
wif = node.toWIF();
|
||||
pubKey = Format.uint8listToString(node.publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < changeDerivations.length; j++) {
|
||||
if (changeDerivations["$j"]["address"] == addresses[i]) {
|
||||
changeDerivation = changeDerivations["$j"];
|
||||
}
|
||||
}
|
||||
if (wif != null && pubKey != null) {
|
||||
final PaymentData data;
|
||||
final Uint8List? redeemScript;
|
||||
|
||||
// final changeDerivation = changeDerivations[addresses[i]];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
switch (sd.derivePathType) {
|
||||
case DerivePathType.bip44:
|
||||
data = P2PKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["publicKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addresses[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: _network,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
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) {
|
||||
Logging.instance
|
||||
.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
|
||||
Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<isar_models.UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
|
@ -1763,10 +1777,14 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
txb.setVersion(1);
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List);
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
|
@ -1776,13 +1794,12 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||
keyPair: utxoSigningData[i].keyPair!,
|
||||
witnessValue: utxoSigningData[i].utxo.value,
|
||||
redeemScript: utxoSigningData[i].redeemScript,
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
|||
import 'package:stackwallet/models/balance.dart';
|
||||
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/signing_data.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/refresh_percent_changed_event.dart';
|
||||
|
@ -1058,13 +1059,15 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
isSendAll = true;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: utxos is List<isar_models.UTXO>,
|
||||
coinControl: coinControl,
|
||||
);
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -2314,6 +2317,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
} else {
|
||||
satoshisBeingUsed = spendableSatoshiValue;
|
||||
utxoObjectsToUse = spendableOutputs;
|
||||
inputsBeingConsumed = spendableOutputs.length;
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
|
@ -2335,7 +2339,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -2353,7 +2356,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: [amount],
|
||||
|
@ -2364,19 +2366,17 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": amount,
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
))["vSize"] as int;
|
||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [
|
||||
recipientAddress,
|
||||
|
@ -2442,7 +2442,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2470,7 +2469,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||
level: LogLevel.Info);
|
||||
txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2483,7 +2481,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2500,7 +2498,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2511,7 +2508,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2530,7 +2527,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2541,7 +2537,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2560,7 +2556,6 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2571,7 +2566,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2597,245 +2592,146 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
Future<List<SigningData>> fetchBuildTxData(
|
||||
List<isar_models.UTXO> utxosToUse,
|
||||
) async {
|
||||
// return data
|
||||
Map<String, dynamic> results = {};
|
||||
Map<String, List<String>> addressTxid = {};
|
||||
|
||||
// addresses to check
|
||||
List<String> addressesP2PKH = [];
|
||||
List<String> addressesP2SH = [];
|
||||
List<String> addressesP2WPKH = [];
|
||||
List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
txHash: txid,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
for (final output in tx["vout"] as List) {
|
||||
final n = output["n"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = output["scriptPubKey"]["addresses"][0] 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");
|
||||
if (utxosToUse[i].address == null) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||
|
||||
signingData.add(
|
||||
SigningData(
|
||||
derivePathType: derivePathType,
|
||||
utxo: utxosToUse[i],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// p2pkh / bip44
|
||||
final p2pkhLength = addressesP2PKH.length;
|
||||
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;
|
||||
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[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[addressesP2PKH[i]];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
for (final sd in signingData) {
|
||||
String? pubKey;
|
||||
String? wif;
|
||||
|
||||
// fetch receiving derivations if null
|
||||
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||
chain: 0,
|
||||
derivePathType: sd.derivePathType,
|
||||
);
|
||||
final receiveDerivation =
|
||||
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||
|
||||
if (receiveDerivation != null) {
|
||||
pubKey = receiveDerivation["pubKey"] as String;
|
||||
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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
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) {
|
||||
case DerivePathType.bip49:
|
||||
final p2wpkh = P2WPKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
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,
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
};
|
||||
}
|
||||
} 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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
network: _network,
|
||||
overridePrefix: _network.bech32!)
|
||||
.data;
|
||||
network: _network,
|
||||
overridePrefix: _network.bech32!,
|
||||
).data;
|
||||
redeemScript = p2wpkh.output;
|
||||
data = P2SH(
|
||||
data: PaymentData(redeem: p2wpkh),
|
||||
network: _network,
|
||||
).data;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: _network,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
case DerivePathType.bip84:
|
||||
data = P2WPKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
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) {
|
||||
Logging.instance
|
||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||
|
@ -2845,8 +2741,7 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
|
||||
/// Builds and signs a transaction
|
||||
Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<isar_models.UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
|
@ -2857,10 +2752,15 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
txb.setVersion(1);
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List, _network.bech32!);
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
_network.bech32!,
|
||||
);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
|
@ -2870,14 +2770,14 @@ class LitecoinWallet extends CoinServiceAPI
|
|||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||
overridePrefix: _network.bech32!);
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[i].keyPair!,
|
||||
witnessValue: utxoSigningData[i].utxo.value,
|
||||
redeemScript: utxoSigningData[i].redeemScript,
|
||||
overridePrefix: _network.bech32!,
|
||||
);
|
||||
}
|
||||
} catch (e, 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/isar/models/isar_models.dart' as isar_models;
|
||||
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/event_bus/events/global/node_connection_status_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;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: utxos is List<isar_models.UTXO>,
|
||||
coinControl: coinControl,
|
||||
);
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -2307,6 +2310,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
} else {
|
||||
satoshisBeingUsed = spendableSatoshiValue;
|
||||
utxoObjectsToUse = spendableOutputs;
|
||||
inputsBeingConsumed = spendableOutputs.length;
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
|
@ -2328,7 +2332,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -2346,7 +2349,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: [amount],
|
||||
|
@ -2357,19 +2359,17 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": amount,
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
))["vSize"] as int;
|
||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [
|
||||
recipientAddress,
|
||||
|
@ -2435,7 +2435,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2463,7 +2462,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||
level: LogLevel.Info);
|
||||
txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2476,7 +2474,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2493,7 +2491,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2504,7 +2501,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2523,7 +2520,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2534,7 +2530,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2553,7 +2549,6 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2564,7 +2559,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2590,248 +2585,144 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
Future<List<SigningData>> fetchBuildTxData(
|
||||
List<isar_models.UTXO> utxosToUse,
|
||||
) async {
|
||||
// return data
|
||||
Map<String, dynamic> results = {};
|
||||
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);
|
||||
List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = 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");
|
||||
if (utxosToUse[i].address == null) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||
|
||||
signingData.add(
|
||||
SigningData(
|
||||
derivePathType: derivePathType,
|
||||
utxo: utxosToUse[i],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// p2pkh / bip44
|
||||
final p2pkhLength = addressesP2PKH.length;
|
||||
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;
|
||||
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[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[addressesP2PKH[i]];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
for (final sd in signingData) {
|
||||
String? pubKey;
|
||||
String? wif;
|
||||
|
||||
// fetch receiving derivations if null
|
||||
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||
chain: 0,
|
||||
derivePathType: sd.derivePathType,
|
||||
);
|
||||
final receiveDerivation =
|
||||
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||
|
||||
if (receiveDerivation != null) {
|
||||
pubKey = receiveDerivation["pubKey"] as String;
|
||||
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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
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) {
|
||||
case DerivePathType.bip49:
|
||||
final p2wpkh = P2WPKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
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,
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
};
|
||||
}
|
||||
} 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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
network: _network,
|
||||
overridePrefix: namecoin.bech32!)
|
||||
network: _network,
|
||||
overridePrefix: _network.bech32!,
|
||||
).data;
|
||||
redeemScript = p2wpkh.output;
|
||||
data = P2SH(data: PaymentData(redeem: p2wpkh), network: _network)
|
||||
.data;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: _network,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
case DerivePathType.bip84:
|
||||
data = P2WPKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
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) {
|
||||
Logging.instance
|
||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||
|
@ -2841,8 +2732,7 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
|
||||
/// Builds and signs a transaction
|
||||
Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<isar_models.UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
|
@ -2853,10 +2743,15 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
txb.setVersion(2);
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List, namecoin.bech32!);
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
_network.bech32!,
|
||||
);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
|
@ -2866,14 +2761,15 @@ class NamecoinWallet extends CoinServiceAPI
|
|||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?,
|
||||
overridePrefix: namecoin.bech32!);
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
_network.bech32!,
|
||||
);
|
||||
}
|
||||
} catch (e, 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/isar/models/isar_models.dart' as isar_models;
|
||||
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/event_bus/events/global/node_connection_status_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;
|
||||
}
|
||||
|
||||
final bool coinControl = utxos != null;
|
||||
|
||||
final txData = await coinSelection(
|
||||
satoshiAmountToSend: satoshiAmount,
|
||||
selectedTxFeeRate: rate,
|
||||
recipientAddress: address,
|
||||
isSendAll: isSendAll,
|
||||
utxos: utxos?.toList(),
|
||||
coinControl: utxos is List<isar_models.UTXO>,
|
||||
coinControl: coinControl,
|
||||
);
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
|
@ -2468,6 +2471,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
} else {
|
||||
satoshisBeingUsed = spendableSatoshiValue;
|
||||
utxoObjectsToUse = spendableOutputs;
|
||||
inputsBeingConsumed = spendableOutputs.length;
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
|
@ -2489,7 +2493,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
.log("Attempting to send all $coin", level: LogLevel.Info);
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
|
@ -2507,7 +2510,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
|
||||
final int amount = satoshiAmountToSend - feeForOneOutput;
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: [amount],
|
||||
|
@ -2518,19 +2520,17 @@ class ParticlWallet extends CoinServiceAPI
|
|||
"recipientAmt": amount,
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
||||
final int vSizeForOneOutput = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [recipientAddress],
|
||||
satoshiAmounts: [satoshisBeingUsed - 1],
|
||||
))["vSize"] as int;
|
||||
final int vSizeForTwoOutPuts = (await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: [
|
||||
recipientAddress,
|
||||
|
@ -2596,7 +2596,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForTwoOutputs', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2624,7 +2623,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
Logging.instance.log('Adjusted Estimated fee: $feeForTwoOutputs',
|
||||
level: LogLevel.Info);
|
||||
txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2637,7 +2635,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2654,7 +2652,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2665,7 +2662,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2684,7 +2681,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2695,7 +2691,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": satoshisBeingUsed - satoshiAmountToSend,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -2714,7 +2710,6 @@ class ParticlWallet extends CoinServiceAPI
|
|||
Logging.instance
|
||||
.log('Estimated fee: $feeForOneOutput', level: LogLevel.Info);
|
||||
dynamic txn = await buildTransaction(
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
recipients: recipientsArray,
|
||||
satoshiAmounts: recipientsAmtArray,
|
||||
|
@ -2725,7 +2720,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
"recipientAmt": recipientsAmtArray[0],
|
||||
"fee": feeForOneOutput,
|
||||
"vSize": txn["vSize"],
|
||||
"usedUTXOs": utxoObjectsToUse,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -2751,168 +2746,130 @@ class ParticlWallet extends CoinServiceAPI
|
|||
}
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
Future<List<SigningData>> fetchBuildTxData(
|
||||
List<isar_models.UTXO> utxosToUse,
|
||||
) async {
|
||||
// return data
|
||||
Map<String, dynamic> results = {};
|
||||
Map<String, List<String>> addressTxid = {};
|
||||
|
||||
// addresses to check
|
||||
List<String> addressesP2PKH = [];
|
||||
List<String> addressesP2WPKH = [];
|
||||
List<SigningData> signingData = [];
|
||||
|
||||
try {
|
||||
// Populating the addresses to check
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
txHash: txid,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
for (final output in tx["vout"] as List) {
|
||||
final n = output["n"];
|
||||
if (n != null && n == utxosToUse[i].vout) {
|
||||
final address = output["scriptPubKey"]["addresses"][0] 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.bip84:
|
||||
addressesP2WPKH.add(address);
|
||||
break;
|
||||
default:
|
||||
throw Exception(
|
||||
"DerivePathType ${addressType(address: address)} not supported");
|
||||
if (utxosToUse[i].address == null) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
final tx = await _cachedElectrumXClient.getTransaction(
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final derivePathType = addressType(address: utxosToUse[i].address!);
|
||||
|
||||
signingData.add(
|
||||
SigningData(
|
||||
derivePathType: derivePathType,
|
||||
utxo: utxosToUse[i],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// p2pkh / bip44
|
||||
final p2pkhLength = addressesP2PKH.length;
|
||||
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;
|
||||
Map<DerivePathType, Map<String, dynamic>> receiveDerivations = {};
|
||||
Map<DerivePathType, Map<String, dynamic>> changeDerivations = {};
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[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[addressesP2PKH[i]];
|
||||
// if a match exists it will not be null
|
||||
if (changeDerivation != null) {
|
||||
final data = P2PKH(
|
||||
for (final sd in signingData) {
|
||||
String? pubKey;
|
||||
String? wif;
|
||||
|
||||
// fetch receiving derivations if null
|
||||
receiveDerivations[sd.derivePathType] ??= await _fetchDerivations(
|
||||
chain: 0,
|
||||
derivePathType: sd.derivePathType,
|
||||
);
|
||||
final receiveDerivation =
|
||||
receiveDerivations[sd.derivePathType]![sd.utxo.address!];
|
||||
|
||||
if (receiveDerivation != null) {
|
||||
pubKey = receiveDerivation["pubKey"] as String;
|
||||
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(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2PKH[i]]!) {
|
||||
results[tx] = {
|
||||
"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(
|
||||
case DerivePathType.bip84:
|
||||
data = P2WPKH(
|
||||
data: PaymentData(
|
||||
pubkey: Format.stringToUint8List(
|
||||
changeDerivation["pubKey"] as String)),
|
||||
pubkey: Format.stringToUint8List(pubKey),
|
||||
),
|
||||
network: _network,
|
||||
).data;
|
||||
redeemScript = null;
|
||||
break;
|
||||
|
||||
for (String tx in addressTxid[addressesP2WPKH[i]]!) {
|
||||
results[tx] = {
|
||||
"output": data.output,
|
||||
"keyPair": ECPair.fromWIF(
|
||||
changeDerivation["wif"] as String,
|
||||
network: _network,
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw Exception("DerivePathType unsupported");
|
||||
}
|
||||
|
||||
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 results;
|
||||
|
||||
return signingData;
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("fetchBuildTxData() threw: $e,\n$s", level: LogLevel.Error);
|
||||
|
@ -2922,8 +2879,7 @@ class ParticlWallet extends CoinServiceAPI
|
|||
|
||||
/// Builds and signs a transaction
|
||||
Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<isar_models.UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required List<String> recipients,
|
||||
required List<int> satoshiAmounts,
|
||||
}) async {
|
||||
|
@ -2937,11 +2893,15 @@ class ParticlWallet extends CoinServiceAPI
|
|||
txb.setVersion(160);
|
||||
|
||||
// Add transaction inputs
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
|
||||
txb.addInput(txid, utxosToUse[i].vout, null,
|
||||
utxoSigningData[txid]["output"] as Uint8List, '');
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
final txid = utxoSigningData[i].utxo.txid;
|
||||
txb.addInput(
|
||||
txid,
|
||||
utxoSigningData[i].utxo.vout,
|
||||
null,
|
||||
utxoSigningData[i].output!,
|
||||
'',
|
||||
);
|
||||
}
|
||||
|
||||
// Add transaction output
|
||||
|
@ -2951,13 +2911,13 @@ class ParticlWallet extends CoinServiceAPI
|
|||
|
||||
try {
|
||||
// Sign the transaction accordingly
|
||||
for (var i = 0; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
for (var i = 0; i < utxoSigningData.length; i++) {
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
redeemScript: utxoSigningData[txid]["redeemScript"] as Uint8List?);
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[i].keyPair!,
|
||||
witnessValue: utxoSigningData[i].utxo.value,
|
||||
redeemScript: utxoSigningData[i].redeemScript,
|
||||
);
|
||||
}
|
||||
} catch (e, 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/paynym_send_exception.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/bip47_utils.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -57,7 +58,7 @@ mixin PaynymWalletInterface {
|
|||
late final Future<int> Function({
|
||||
required String address,
|
||||
}) _getTxCount;
|
||||
late final Future<Map<String, dynamic>> Function(
|
||||
late final Future<List<SigningData>> Function(
|
||||
List<UTXO> utxosToUse,
|
||||
) _fetchBuildTxData;
|
||||
late final Future<void> Function() _refresh;
|
||||
|
@ -100,7 +101,7 @@ mixin PaynymWalletInterface {
|
|||
required String address,
|
||||
})
|
||||
getTxCount,
|
||||
required Future<Map<String, dynamic>> Function(
|
||||
required Future<List<SigningData>> Function(
|
||||
List<UTXO> utxosToUse,
|
||||
)
|
||||
fetchBuildTxData,
|
||||
|
@ -455,7 +456,6 @@ mixin PaynymWalletInterface {
|
|||
|
||||
final int vSizeForNoChange = (await _createNotificationTx(
|
||||
targetPaymentCodeString: targetPaymentCodeString,
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
change: 0,
|
||||
dustLimit:
|
||||
|
@ -465,7 +465,6 @@ mixin PaynymWalletInterface {
|
|||
|
||||
final int vSizeForWithChange = (await _createNotificationTx(
|
||||
targetPaymentCodeString: targetPaymentCodeString,
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
change: satoshisBeingUsed - amountToSend,
|
||||
))
|
||||
|
@ -503,7 +502,6 @@ mixin PaynymWalletInterface {
|
|||
feeForWithChange) {
|
||||
var txn = await _createNotificationTx(
|
||||
targetPaymentCodeString: targetPaymentCodeString,
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
change: changeAmount,
|
||||
);
|
||||
|
@ -516,7 +514,6 @@ mixin PaynymWalletInterface {
|
|||
feeBeingPaid += 1;
|
||||
txn = await _createNotificationTx(
|
||||
targetPaymentCodeString: targetPaymentCodeString,
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
change: changeAmount,
|
||||
);
|
||||
|
@ -528,6 +525,7 @@ mixin PaynymWalletInterface {
|
|||
"amount": amountToSend,
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn.item2,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -535,7 +533,6 @@ mixin PaynymWalletInterface {
|
|||
// than the dust limit. Try without change
|
||||
final txn = await _createNotificationTx(
|
||||
targetPaymentCodeString: targetPaymentCodeString,
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
change: 0,
|
||||
);
|
||||
|
@ -548,6 +545,7 @@ mixin PaynymWalletInterface {
|
|||
"amount": amountToSend,
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn.item2,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
}
|
||||
|
@ -556,7 +554,6 @@ mixin PaynymWalletInterface {
|
|||
// build without change here
|
||||
final txn = await _createNotificationTx(
|
||||
targetPaymentCodeString: targetPaymentCodeString,
|
||||
utxosToUse: utxoObjectsToUse,
|
||||
utxoSigningData: utxoSigningData,
|
||||
change: 0,
|
||||
);
|
||||
|
@ -569,6 +566,7 @@ mixin PaynymWalletInterface {
|
|||
"amount": amountToSend,
|
||||
"fee": feeBeingPaid,
|
||||
"vSize": txn.item2,
|
||||
"usedUTXOs": utxoSigningData.map((e) => e.utxo).toList(),
|
||||
};
|
||||
return transactionObject;
|
||||
} else {
|
||||
|
@ -594,8 +592,7 @@ mixin PaynymWalletInterface {
|
|||
// equal to its vSize
|
||||
Future<Tuple2<String, int>> _createNotificationTx({
|
||||
required String targetPaymentCodeString,
|
||||
required List<UTXO> utxosToUse,
|
||||
required Map<String, dynamic> utxoSigningData,
|
||||
required List<SigningData> utxoSigningData,
|
||||
required int change,
|
||||
int? dustLimit,
|
||||
}) async {
|
||||
|
@ -604,7 +601,7 @@ mixin PaynymWalletInterface {
|
|||
PaymentCode.fromPaymentCode(targetPaymentCodeString, _network);
|
||||
final myCode = await getPaymentCode(DerivePathType.bip44);
|
||||
|
||||
final utxo = utxosToUse.first;
|
||||
final utxo = utxoSigningData.first.utxo;
|
||||
final txPoint = utxo.txid.fromHex.reversed.toList();
|
||||
final txPointIndex = utxo.vout;
|
||||
|
||||
|
@ -613,8 +610,7 @@ mixin PaynymWalletInterface {
|
|||
final buffer = rev.buffer.asByteData();
|
||||
buffer.setUint32(txPoint.length, txPointIndex, Endian.little);
|
||||
|
||||
final myKeyPair =
|
||||
utxoSigningData[utxo.txid]["keyPair"] as btc_dart.ECPair;
|
||||
final myKeyPair = utxoSigningData.first.keyPair!;
|
||||
|
||||
final S = SecretPoint(
|
||||
myKeyPair.privateKey!,
|
||||
|
@ -642,17 +638,17 @@ mixin PaynymWalletInterface {
|
|||
utxo.txid,
|
||||
txPointIndex,
|
||||
null,
|
||||
utxoSigningData[utxo.txid]["output"] as Uint8List,
|
||||
utxoSigningData.first.output!,
|
||||
);
|
||||
|
||||
// add rest of possible inputs
|
||||
for (var i = 1; i < utxosToUse.length; i++) {
|
||||
final utxo = utxosToUse[i];
|
||||
for (var i = 1; i < utxoSigningData.length; i++) {
|
||||
final utxo = utxoSigningData[i].utxo;
|
||||
txb.addInput(
|
||||
utxo.txid,
|
||||
utxo.vout,
|
||||
null,
|
||||
utxoSigningData[utxo.txid]["output"] as Uint8List,
|
||||
utxoSigningData[i].output!,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -675,18 +671,16 @@ mixin PaynymWalletInterface {
|
|||
vin: 0,
|
||||
keyPair: myKeyPair,
|
||||
witnessValue: utxo.value,
|
||||
witnessScript: utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?,
|
||||
witnessScript: utxoSigningData.first.redeemScript,
|
||||
);
|
||||
|
||||
// sign rest of possible inputs
|
||||
for (var i = 1; i < utxosToUse.length; i++) {
|
||||
final txid = utxosToUse[i].txid;
|
||||
for (var i = 1; i < utxoSigningData.length; i++) {
|
||||
txb.sign(
|
||||
vin: i,
|
||||
keyPair: utxoSigningData[txid]["keyPair"] as btc_dart.ECPair,
|
||||
witnessValue: utxosToUse[i].value,
|
||||
witnessScript:
|
||||
utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?,
|
||||
keyPair: utxoSigningData[i].keyPair!,
|
||||
witnessValue: utxoSigningData[i].utxo.value,
|
||||
witnessScript: utxoSigningData[i].redeemScript,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,20 +21,24 @@ class StackDialogBase extends StatelessWidget {
|
|||
mainAxisAlignment:
|
||||
!Util.isDesktop ? MainAxisAlignment.end : MainAxisAlignment.center,
|
||||
children: [
|
||||
Material(
|
||||
borderRadius: BorderRadius.circular(
|
||||
20,
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
Flexible(
|
||||
child: SingleChildScrollView(
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(
|
||||
20,
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: padding,
|
||||
child: child,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
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
|
||||
git clone https://github.com/flutter/flutter.git
|
||||
cd flutter
|
||||
git checkout 3.3.4
|
||||
git checkout 3.7.6
|
||||
export FLUTTER_DIR=$(pwd)/bin
|
||||
echo 'export PATH="$PATH:'${FLUTTER_DIR}'"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i22;
|
||||
import 'dart:typed_data' as _i28;
|
||||
import 'dart:typed_data' as _i29;
|
||||
import 'dart:ui' as _i24;
|
||||
|
||||
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/node_model.dart' as _i25;
|
||||
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/coin_service.dart' as _i19;
|
||||
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/transaction_notification_tracker.dart'
|
||||
as _i8;
|
||||
import 'package:stackwallet/services/wallets.dart' as _i20;
|
||||
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/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'
|
||||
as _i7;
|
||||
import 'package:stackwallet/utilities/prefs.dart' as _i23;
|
||||
|
@ -1438,7 +1439,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i22.Future<List<_i28.SigningData>> fetchBuildTxData(
|
||||
List<_i16.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -1446,12 +1447,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i22.Future<Map<String, dynamic>>);
|
||||
_i22.Future<List<_i28.SigningData>>.value(<_i28.SigningData>[]),
|
||||
) as _i22.Future<List<_i28.SigningData>>);
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i16.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i28.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1460,7 +1460,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -1714,7 +1713,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
})?
|
||||
prepareSend,
|
||||
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,
|
||||
required _i22.Future<void> Function()? refresh,
|
||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||
|
@ -1866,14 +1865,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
)),
|
||||
) as _i22.Future<_i18.PaymentCode>);
|
||||
@override
|
||||
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||
_i22.Future<_i29.Uint8List> signWithNotificationKey(_i29.Uint8List? data) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#signWithNotificationKey,
|
||||
[data],
|
||||
),
|
||||
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||
) as _i22.Future<_i28.Uint8List>);
|
||||
returnValue: _i22.Future<_i29.Uint8List>.value(_i29.Uint8List(0)),
|
||||
) as _i22.Future<_i29.Uint8List>);
|
||||
@override
|
||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2209,7 +2208,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i26.BitcoinWallet {
|
|||
/// A class which mocks [LocaleService].
|
||||
///
|
||||
/// 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() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
@ -2327,12 +2326,12 @@ class MockPrefs extends _i1.Mock implements _i23.Prefs {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i30.SyncingType get syncType => (super.noSuchMethod(
|
||||
_i31.SyncingType get syncType => (super.noSuchMethod(
|
||||
Invocation.getter(#syncType),
|
||||
returnValue: _i30.SyncingType.currentWalletOnly,
|
||||
) as _i30.SyncingType);
|
||||
returnValue: _i31.SyncingType.currentWalletOnly,
|
||||
) as _i31.SyncingType);
|
||||
@override
|
||||
set syncType(_i30.SyncingType? syncType) => super.noSuchMethod(
|
||||
set syncType(_i31.SyncingType? syncType) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#syncType,
|
||||
syncType,
|
||||
|
@ -2465,12 +2464,12 @@ class MockPrefs extends _i1.Mock implements _i23.Prefs {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i31.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
||||
_i32.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
||||
Invocation.getter(#backupFrequencyType),
|
||||
returnValue: _i31.BackupFrequencyType.everyTenMinutes,
|
||||
) as _i31.BackupFrequencyType);
|
||||
returnValue: _i32.BackupFrequencyType.everyTenMinutes,
|
||||
) as _i32.BackupFrequencyType);
|
||||
@override
|
||||
set backupFrequencyType(_i31.BackupFrequencyType? backupFrequencyType) =>
|
||||
set backupFrequencyType(_i32.BackupFrequencyType? backupFrequencyType) =>
|
||||
super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#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/models/balance.dart' as _i6;
|
||||
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/signing_data.dart' as _i13;
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart' as _i9;
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||
as _i2;
|
||||
|
@ -485,7 +486,7 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i10.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i10.Future<List<_i13.SigningData>> fetchBuildTxData(
|
||||
List<_i12.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -493,12 +494,11 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i10.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i10.Future<Map<String, dynamic>>);
|
||||
_i10.Future<List<_i13.SigningData>>.value(<_i13.SigningData>[]),
|
||||
) as _i10.Future<List<_i13.SigningData>>);
|
||||
@override
|
||||
_i10.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i12.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i13.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -507,7 +507,6 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -570,14 +569,14 @@ class MockFiroWallet extends _i1.Mock implements _i9.FiroWallet {
|
|||
returnValueForMissingStub: _i10.Future<void>.value(),
|
||||
) as _i10.Future<void>);
|
||||
@override
|
||||
List<Map<dynamic, _i13.LelantusCoin>> getLelantusCoinMap() =>
|
||||
List<Map<dynamic, _i14.LelantusCoin>> getLelantusCoinMap() =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getLelantusCoinMap,
|
||||
[],
|
||||
),
|
||||
returnValue: <Map<dynamic, _i13.LelantusCoin>>[],
|
||||
) as List<Map<dynamic, _i13.LelantusCoin>>);
|
||||
returnValue: <Map<dynamic, _i14.LelantusCoin>>[],
|
||||
) as List<Map<dynamic, _i14.LelantusCoin>>);
|
||||
@override
|
||||
_i10.Future<void> anonymizeAllPublicFunds() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i22;
|
||||
import 'dart:typed_data' as _i27;
|
||||
import 'dart:typed_data' as _i28;
|
||||
import 'dart:ui' as _i24;
|
||||
|
||||
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/models/balance.dart' as _i11;
|
||||
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/signing_data.dart' as _i27;
|
||||
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/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/transaction_notification_tracker.dart'
|
||||
as _i7;
|
||||
|
@ -1230,7 +1231,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i22.Future<List<_i27.SigningData>> fetchBuildTxData(
|
||||
List<_i15.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -1238,12 +1239,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i22.Future<Map<String, dynamic>>);
|
||||
_i22.Future<List<_i27.SigningData>>.value(<_i27.SigningData>[]),
|
||||
) as _i22.Future<List<_i27.SigningData>>);
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i15.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i27.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1252,7 +1252,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -1506,7 +1505,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
})?
|
||||
prepareSend,
|
||||
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,
|
||||
required _i22.Future<void> Function()? refresh,
|
||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||
|
@ -1658,14 +1657,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
)),
|
||||
) as _i22.Future<_i17.PaymentCode>);
|
||||
@override
|
||||
_i22.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
||||
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#signWithNotificationKey,
|
||||
[data],
|
||||
),
|
||||
returnValue: _i22.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
||||
) as _i22.Future<_i27.Uint8List>);
|
||||
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||
) as _i22.Future<_i28.Uint8List>);
|
||||
@override
|
||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2001,7 +2000,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
/// A class which mocks [LocaleService].
|
||||
///
|
||||
/// 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() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
@ -2073,15 +2072,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
),
|
||||
) as _i18.SecureStorageInterface);
|
||||
@override
|
||||
List<_i29.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
List<_i30.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
returnValue: <_i30.NodeModel>[],
|
||||
) as List<_i30.NodeModel>);
|
||||
@override
|
||||
List<_i29.NodeModel> get nodes => (super.noSuchMethod(
|
||||
List<_i30.NodeModel> get nodes => (super.noSuchMethod(
|
||||
Invocation.getter(#nodes),
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
returnValue: <_i30.NodeModel>[],
|
||||
) as List<_i30.NodeModel>);
|
||||
@override
|
||||
bool get hasListeners => (super.noSuchMethod(
|
||||
Invocation.getter(#hasListeners),
|
||||
|
@ -2099,7 +2098,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
@override
|
||||
_i22.Future<void> setPrimaryNodeFor({
|
||||
required _i21.Coin? coin,
|
||||
required _i29.NodeModel? node,
|
||||
required _i30.NodeModel? node,
|
||||
bool? shouldNotifyListeners = false,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2116,40 +2115,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
returnValueForMissingStub: _i22.Future<void>.value(),
|
||||
) as _i22.Future<void>);
|
||||
@override
|
||||
_i29.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||
_i30.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||
(super.noSuchMethod(Invocation.method(
|
||||
#getPrimaryNodeFor,
|
||||
[],
|
||||
{#coin: coin},
|
||||
)) as _i29.NodeModel?);
|
||||
)) as _i30.NodeModel?);
|
||||
@override
|
||||
List<_i29.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||
List<_i30.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getNodesFor,
|
||||
[coin],
|
||||
),
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
returnValue: <_i30.NodeModel>[],
|
||||
) as List<_i30.NodeModel>);
|
||||
@override
|
||||
_i29.NodeModel? getNodeById({required String? id}) =>
|
||||
_i30.NodeModel? getNodeById({required String? id}) =>
|
||||
(super.noSuchMethod(Invocation.method(
|
||||
#getNodeById,
|
||||
[],
|
||||
{#id: id},
|
||||
)) as _i29.NodeModel?);
|
||||
)) as _i30.NodeModel?);
|
||||
@override
|
||||
List<_i29.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||
List<_i30.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#failoverNodesFor,
|
||||
[],
|
||||
{#coin: coin},
|
||||
),
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
returnValue: <_i30.NodeModel>[],
|
||||
) as List<_i30.NodeModel>);
|
||||
@override
|
||||
_i22.Future<void> add(
|
||||
_i29.NodeModel? node,
|
||||
_i30.NodeModel? node,
|
||||
String? password,
|
||||
bool? shouldNotifyListeners,
|
||||
) =>
|
||||
|
@ -2201,7 +2200,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
) as _i22.Future<void>);
|
||||
@override
|
||||
_i22.Future<void> edit(
|
||||
_i29.NodeModel? editedNode,
|
||||
_i30.NodeModel? editedNode,
|
||||
String? password,
|
||||
bool? shouldNotifyListeners,
|
||||
) =>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i21;
|
||||
import 'dart:typed_data' as _i27;
|
||||
import 'dart:typed_data' as _i28;
|
||||
import 'dart:ui' as _i23;
|
||||
|
||||
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/isar/models/isar_models.dart' as _i15;
|
||||
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/coin_service.dart' as _i18;
|
||||
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/derive_path_type_enum.dart' as _i25;
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
||||
as _i26;
|
||||
as _i27;
|
||||
import 'package:stackwallet/utilities/prefs.dart' as _i22;
|
||||
import 'package:tuple/tuple.dart' as _i14;
|
||||
|
||||
|
@ -1217,7 +1218,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i21.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i21.Future<List<_i26.SigningData>> fetchBuildTxData(
|
||||
List<_i15.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -1225,12 +1226,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i21.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i21.Future<Map<String, dynamic>>);
|
||||
_i21.Future<List<_i26.SigningData>>.value(<_i26.SigningData>[]),
|
||||
) as _i21.Future<List<_i26.SigningData>>);
|
||||
@override
|
||||
_i21.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i15.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i26.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1239,7 +1239,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -1474,7 +1473,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
required _i20.Coin? coin,
|
||||
required _i12.MainDB? db,
|
||||
required _i9.ElectrumX? electrumXClient,
|
||||
required _i26.SecureStorageInterface? secureStorage,
|
||||
required _i27.SecureStorageInterface? secureStorage,
|
||||
required int? dustLimitP2PKH,
|
||||
required int? minConfirms,
|
||||
required _i21.Future<String?> Function()? getMnemonicString,
|
||||
|
@ -1493,7 +1492,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
})?
|
||||
prepareSend,
|
||||
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,
|
||||
required _i21.Future<void> Function()? refresh,
|
||||
required _i21.Future<void> Function()? checkChangeAddressForTransactions,
|
||||
|
@ -1645,14 +1644,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i24.BitcoinWallet {
|
|||
)),
|
||||
) as _i21.Future<_i17.PaymentCode>);
|
||||
@override
|
||||
_i21.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
||||
_i21.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#signWithNotificationKey,
|
||||
[data],
|
||||
),
|
||||
returnValue: _i21.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
||||
) as _i21.Future<_i27.Uint8List>);
|
||||
returnValue: _i21.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||
) as _i21.Future<_i28.Uint8List>);
|
||||
@override
|
||||
_i21.Future<String> signStringWithNotificationKey(String? data) =>
|
||||
(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/isar/models/isar_models.dart' as _i21;
|
||||
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/firo/firo_wallet.dart' as _i22;
|
||||
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/notes_service.dart' as _i27;
|
||||
import 'package:stackwallet/services/price_service.dart' as _i26;
|
||||
import 'package:stackwallet/services/notes_service.dart' as _i28;
|
||||
import 'package:stackwallet/services/price_service.dart' as _i27;
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||
as _i10;
|
||||
import 'package:stackwallet/services/wallets.dart' as _i16;
|
||||
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/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:tuple/tuple.dart' as _i15;
|
||||
|
||||
|
@ -1443,7 +1444,7 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i18.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i18.Future<List<_i23.SigningData>> fetchBuildTxData(
|
||||
List<_i21.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -1451,12 +1452,11 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i18.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i18.Future<Map<String, dynamic>>);
|
||||
_i18.Future<List<_i23.SigningData>>.value(<_i23.SigningData>[]),
|
||||
) as _i18.Future<List<_i23.SigningData>>);
|
||||
@override
|
||||
_i18.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i21.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i23.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1465,7 +1465,6 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -2001,7 +2000,7 @@ class MockFiroWallet extends _i1.Mock implements _i22.FiroWallet {
|
|||
/// A class which mocks [LocaleService].
|
||||
///
|
||||
/// 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() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
@ -2119,12 +2118,12 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i24.SyncingType get syncType => (super.noSuchMethod(
|
||||
_i25.SyncingType get syncType => (super.noSuchMethod(
|
||||
Invocation.getter(#syncType),
|
||||
returnValue: _i24.SyncingType.currentWalletOnly,
|
||||
) as _i24.SyncingType);
|
||||
returnValue: _i25.SyncingType.currentWalletOnly,
|
||||
) as _i25.SyncingType);
|
||||
@override
|
||||
set syncType(_i24.SyncingType? syncType) => super.noSuchMethod(
|
||||
set syncType(_i25.SyncingType? syncType) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#syncType,
|
||||
syncType,
|
||||
|
@ -2257,12 +2256,12 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i25.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
||||
_i26.BackupFrequencyType get backupFrequencyType => (super.noSuchMethod(
|
||||
Invocation.getter(#backupFrequencyType),
|
||||
returnValue: _i25.BackupFrequencyType.everyTenMinutes,
|
||||
) as _i25.BackupFrequencyType);
|
||||
returnValue: _i26.BackupFrequencyType.everyTenMinutes,
|
||||
) as _i26.BackupFrequencyType);
|
||||
@override
|
||||
set backupFrequencyType(_i25.BackupFrequencyType? backupFrequencyType) =>
|
||||
set backupFrequencyType(_i26.BackupFrequencyType? backupFrequencyType) =>
|
||||
super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#backupFrequencyType,
|
||||
|
@ -2425,7 +2424,7 @@ class MockPrefs extends _i1.Mock implements _i19.Prefs {
|
|||
/// A class which mocks [PriceService].
|
||||
///
|
||||
/// 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() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
@ -2533,7 +2532,7 @@ class MockPriceService extends _i1.Mock implements _i26.PriceService {
|
|||
/// A class which mocks [NotesService].
|
||||
///
|
||||
/// 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() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i20;
|
||||
import 'dart:typed_data' as _i26;
|
||||
import 'dart:typed_data' as _i27;
|
||||
import 'dart:ui' as _i22;
|
||||
|
||||
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/isar/models/isar_models.dart' as _i15;
|
||||
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/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/transaction_notification_tracker.dart'
|
||||
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/derive_path_type_enum.dart' as _i24;
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
||||
as _i25;
|
||||
as _i26;
|
||||
import 'package:stackwallet/utilities/prefs.dart' as _i21;
|
||||
import 'package:tuple/tuple.dart' as _i14;
|
||||
|
||||
|
@ -980,7 +981,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i20.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i20.Future<List<_i25.SigningData>> fetchBuildTxData(
|
||||
List<_i15.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -988,12 +989,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i20.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i20.Future<Map<String, dynamic>>);
|
||||
_i20.Future<List<_i25.SigningData>>.value(<_i25.SigningData>[]),
|
||||
) as _i20.Future<List<_i25.SigningData>>);
|
||||
@override
|
||||
_i20.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i15.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i25.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1002,7 +1002,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -1237,7 +1236,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
required _i19.Coin? coin,
|
||||
required _i12.MainDB? db,
|
||||
required _i9.ElectrumX? electrumXClient,
|
||||
required _i25.SecureStorageInterface? secureStorage,
|
||||
required _i26.SecureStorageInterface? secureStorage,
|
||||
required int? dustLimitP2PKH,
|
||||
required int? minConfirms,
|
||||
required _i20.Future<String?> Function()? getMnemonicString,
|
||||
|
@ -1256,7 +1255,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
})?
|
||||
prepareSend,
|
||||
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,
|
||||
required _i20.Future<void> Function()? refresh,
|
||||
required _i20.Future<void> Function()? checkChangeAddressForTransactions,
|
||||
|
@ -1408,14 +1407,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
)),
|
||||
) as _i20.Future<_i17.PaymentCode>);
|
||||
@override
|
||||
_i20.Future<_i26.Uint8List> signWithNotificationKey(_i26.Uint8List? data) =>
|
||||
_i20.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#signWithNotificationKey,
|
||||
[data],
|
||||
),
|
||||
returnValue: _i20.Future<_i26.Uint8List>.value(_i26.Uint8List(0)),
|
||||
) as _i20.Future<_i26.Uint8List>);
|
||||
returnValue: _i20.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
||||
) as _i20.Future<_i27.Uint8List>);
|
||||
@override
|
||||
_i20.Future<String> signStringWithNotificationKey(String? data) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -1751,7 +1750,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i23.BitcoinWallet {
|
|||
/// A class which mocks [LocaleService].
|
||||
///
|
||||
/// 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() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i22;
|
||||
import 'dart:typed_data' as _i27;
|
||||
import 'dart:typed_data' as _i28;
|
||||
import 'dart:ui' as _i24;
|
||||
|
||||
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/models/balance.dart' as _i11;
|
||||
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/signing_data.dart' as _i27;
|
||||
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/manager.dart' as _i6;
|
||||
|
@ -1229,7 +1230,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i22.Future<List<_i27.SigningData>> fetchBuildTxData(
|
||||
List<_i15.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -1237,12 +1238,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i22.Future<Map<String, dynamic>>);
|
||||
_i22.Future<List<_i27.SigningData>>.value(<_i27.SigningData>[]),
|
||||
) as _i22.Future<List<_i27.SigningData>>);
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i15.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i27.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1251,7 +1251,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -1505,7 +1504,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
})?
|
||||
prepareSend,
|
||||
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,
|
||||
required _i22.Future<void> Function()? refresh,
|
||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||
|
@ -1657,14 +1656,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
)),
|
||||
) as _i22.Future<_i17.PaymentCode>);
|
||||
@override
|
||||
_i22.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
||||
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#signWithNotificationKey,
|
||||
[data],
|
||||
),
|
||||
returnValue: _i22.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
||||
) as _i22.Future<_i27.Uint8List>);
|
||||
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||
) as _i22.Future<_i28.Uint8List>);
|
||||
@override
|
||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2010,15 +2009,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
),
|
||||
) as _i18.SecureStorageInterface);
|
||||
@override
|
||||
List<_i28.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
List<_i29.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
List<_i28.NodeModel> get nodes => (super.noSuchMethod(
|
||||
List<_i29.NodeModel> get nodes => (super.noSuchMethod(
|
||||
Invocation.getter(#nodes),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
bool get hasListeners => (super.noSuchMethod(
|
||||
Invocation.getter(#hasListeners),
|
||||
|
@ -2036,7 +2035,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
@override
|
||||
_i22.Future<void> setPrimaryNodeFor({
|
||||
required _i21.Coin? coin,
|
||||
required _i28.NodeModel? node,
|
||||
required _i29.NodeModel? node,
|
||||
bool? shouldNotifyListeners = false,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2053,40 +2052,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
returnValueForMissingStub: _i22.Future<void>.value(),
|
||||
) as _i22.Future<void>);
|
||||
@override
|
||||
_i28.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||
_i29.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||
(super.noSuchMethod(Invocation.method(
|
||||
#getPrimaryNodeFor,
|
||||
[],
|
||||
{#coin: coin},
|
||||
)) as _i28.NodeModel?);
|
||||
)) as _i29.NodeModel?);
|
||||
@override
|
||||
List<_i28.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||
List<_i29.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getNodesFor,
|
||||
[coin],
|
||||
),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
_i28.NodeModel? getNodeById({required String? id}) =>
|
||||
_i29.NodeModel? getNodeById({required String? id}) =>
|
||||
(super.noSuchMethod(Invocation.method(
|
||||
#getNodeById,
|
||||
[],
|
||||
{#id: id},
|
||||
)) as _i28.NodeModel?);
|
||||
)) as _i29.NodeModel?);
|
||||
@override
|
||||
List<_i28.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||
List<_i29.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#failoverNodesFor,
|
||||
[],
|
||||
{#coin: coin},
|
||||
),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
_i22.Future<void> add(
|
||||
_i28.NodeModel? node,
|
||||
_i29.NodeModel? node,
|
||||
String? password,
|
||||
bool? shouldNotifyListeners,
|
||||
) =>
|
||||
|
@ -2138,7 +2137,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
) as _i22.Future<void>);
|
||||
@override
|
||||
_i22.Future<void> edit(
|
||||
_i28.NodeModel? editedNode,
|
||||
_i29.NodeModel? editedNode,
|
||||
String? password,
|
||||
bool? shouldNotifyListeners,
|
||||
) =>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i22;
|
||||
import 'dart:typed_data' as _i27;
|
||||
import 'dart:typed_data' as _i28;
|
||||
import 'dart:ui' as _i24;
|
||||
|
||||
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/models/balance.dart' as _i11;
|
||||
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/signing_data.dart' as _i27;
|
||||
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/manager.dart' as _i6;
|
||||
|
@ -1229,7 +1230,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
},
|
||||
));
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> fetchBuildTxData(
|
||||
_i22.Future<List<_i27.SigningData>> fetchBuildTxData(
|
||||
List<_i15.UTXO>? utxosToUse) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -1237,12 +1238,11 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
[utxosToUse],
|
||||
),
|
||||
returnValue:
|
||||
_i22.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i22.Future<Map<String, dynamic>>);
|
||||
_i22.Future<List<_i27.SigningData>>.value(<_i27.SigningData>[]),
|
||||
) as _i22.Future<List<_i27.SigningData>>);
|
||||
@override
|
||||
_i22.Future<Map<String, dynamic>> buildTransaction({
|
||||
required List<_i15.UTXO>? utxosToUse,
|
||||
required Map<String, dynamic>? utxoSigningData,
|
||||
required List<_i27.SigningData>? utxoSigningData,
|
||||
required List<String>? recipients,
|
||||
required List<int>? satoshiAmounts,
|
||||
}) =>
|
||||
|
@ -1251,7 +1251,6 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
#buildTransaction,
|
||||
[],
|
||||
{
|
||||
#utxosToUse: utxosToUse,
|
||||
#utxoSigningData: utxoSigningData,
|
||||
#recipients: recipients,
|
||||
#satoshiAmounts: satoshiAmounts,
|
||||
|
@ -1505,7 +1504,7 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
})?
|
||||
prepareSend,
|
||||
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,
|
||||
required _i22.Future<void> Function()? refresh,
|
||||
required _i22.Future<void> Function()? checkChangeAddressForTransactions,
|
||||
|
@ -1657,14 +1656,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i25.BitcoinWallet {
|
|||
)),
|
||||
) as _i22.Future<_i17.PaymentCode>);
|
||||
@override
|
||||
_i22.Future<_i27.Uint8List> signWithNotificationKey(_i27.Uint8List? data) =>
|
||||
_i22.Future<_i28.Uint8List> signWithNotificationKey(_i28.Uint8List? data) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#signWithNotificationKey,
|
||||
[data],
|
||||
),
|
||||
returnValue: _i22.Future<_i27.Uint8List>.value(_i27.Uint8List(0)),
|
||||
) as _i22.Future<_i27.Uint8List>);
|
||||
returnValue: _i22.Future<_i28.Uint8List>.value(_i28.Uint8List(0)),
|
||||
) as _i22.Future<_i28.Uint8List>);
|
||||
@override
|
||||
_i22.Future<String> signStringWithNotificationKey(String? data) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2010,15 +2009,15 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
),
|
||||
) as _i18.SecureStorageInterface);
|
||||
@override
|
||||
List<_i28.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
List<_i29.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
List<_i28.NodeModel> get nodes => (super.noSuchMethod(
|
||||
List<_i29.NodeModel> get nodes => (super.noSuchMethod(
|
||||
Invocation.getter(#nodes),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
bool get hasListeners => (super.noSuchMethod(
|
||||
Invocation.getter(#hasListeners),
|
||||
|
@ -2036,7 +2035,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
@override
|
||||
_i22.Future<void> setPrimaryNodeFor({
|
||||
required _i21.Coin? coin,
|
||||
required _i28.NodeModel? node,
|
||||
required _i29.NodeModel? node,
|
||||
bool? shouldNotifyListeners = false,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
|
@ -2053,40 +2052,40 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
returnValueForMissingStub: _i22.Future<void>.value(),
|
||||
) as _i22.Future<void>);
|
||||
@override
|
||||
_i28.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||
_i29.NodeModel? getPrimaryNodeFor({required _i21.Coin? coin}) =>
|
||||
(super.noSuchMethod(Invocation.method(
|
||||
#getPrimaryNodeFor,
|
||||
[],
|
||||
{#coin: coin},
|
||||
)) as _i28.NodeModel?);
|
||||
)) as _i29.NodeModel?);
|
||||
@override
|
||||
List<_i28.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||
List<_i29.NodeModel> getNodesFor(_i21.Coin? coin) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getNodesFor,
|
||||
[coin],
|
||||
),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
_i28.NodeModel? getNodeById({required String? id}) =>
|
||||
_i29.NodeModel? getNodeById({required String? id}) =>
|
||||
(super.noSuchMethod(Invocation.method(
|
||||
#getNodeById,
|
||||
[],
|
||||
{#id: id},
|
||||
)) as _i28.NodeModel?);
|
||||
)) as _i29.NodeModel?);
|
||||
@override
|
||||
List<_i28.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||
List<_i29.NodeModel> failoverNodesFor({required _i21.Coin? coin}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#failoverNodesFor,
|
||||
[],
|
||||
{#coin: coin},
|
||||
),
|
||||
returnValue: <_i28.NodeModel>[],
|
||||
) as List<_i28.NodeModel>);
|
||||
returnValue: <_i29.NodeModel>[],
|
||||
) as List<_i29.NodeModel>);
|
||||
@override
|
||||
_i22.Future<void> add(
|
||||
_i28.NodeModel? node,
|
||||
_i29.NodeModel? node,
|
||||
String? password,
|
||||
bool? shouldNotifyListeners,
|
||||
) =>
|
||||
|
@ -2138,7 +2137,7 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
) as _i22.Future<void>);
|
||||
@override
|
||||
_i22.Future<void> edit(
|
||||
_i28.NodeModel? editedNode,
|
||||
_i29.NodeModel? editedNode,
|
||||
String? password,
|
||||
bool? shouldNotifyListeners,
|
||||
) =>
|
||||
|
|
Loading…
Reference in a new issue