mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-09 12:29:31 +00:00
Merge remote-tracking branch 'origin/electrum-sp-refactors' into electrum-sp-refactors
This commit is contained in:
commit
a169db7e51
9 changed files with 109 additions and 134 deletions
|
@ -439,8 +439,8 @@ abstract class ElectrumWalletBase
|
|||
|
||||
TxCreateUtxoDetails _createUTXOS({
|
||||
required bool sendAll,
|
||||
required int credentialsAmount,
|
||||
required bool paysToSilentPayment,
|
||||
int credentialsAmount = 0,
|
||||
int? inputsCount,
|
||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||
}) {
|
||||
|
@ -574,13 +574,11 @@ abstract class ElectrumWalletBase
|
|||
List<BitcoinOutput> outputs,
|
||||
int feeRate, {
|
||||
String? memo,
|
||||
int credentialsAmount = 0,
|
||||
bool hasSilentPayment = false,
|
||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||
}) async {
|
||||
final utxoDetails = _createUTXOS(
|
||||
sendAll: true,
|
||||
credentialsAmount: credentialsAmount,
|
||||
paysToSilentPayment: hasSilentPayment,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
|
@ -603,23 +601,11 @@ abstract class ElectrumWalletBase
|
|||
throw BitcoinTransactionWrongBalanceException(amount: utxoDetails.allInputsAmount + fee);
|
||||
}
|
||||
|
||||
if (amount <= 0) {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
}
|
||||
|
||||
// Attempting to send less than the dust limit
|
||||
if (_isBelowDust(amount)) {
|
||||
throw BitcoinTransactionNoDustException();
|
||||
}
|
||||
|
||||
if (credentialsAmount > 0) {
|
||||
final amountLeftForFee = amount - credentialsAmount;
|
||||
if (amountLeftForFee > 0 && _isBelowDust(amountLeftForFee)) {
|
||||
amount -= amountLeftForFee;
|
||||
fee += amountLeftForFee;
|
||||
}
|
||||
}
|
||||
|
||||
if (outputs.length == 1) {
|
||||
outputs[0] = BitcoinOutput(address: outputs.last.address, value: BigInt.from(amount));
|
||||
}
|
||||
|
@ -649,6 +635,11 @@ abstract class ElectrumWalletBase
|
|||
bool hasSilentPayment = false,
|
||||
UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any,
|
||||
}) async {
|
||||
// Attempting to send less than the dust limit
|
||||
if (_isBelowDust(credentialsAmount)) {
|
||||
throw BitcoinTransactionNoDustException();
|
||||
}
|
||||
|
||||
final utxoDetails = _createUTXOS(
|
||||
sendAll: false,
|
||||
credentialsAmount: credentialsAmount,
|
||||
|
@ -726,7 +717,43 @@ abstract class ElectrumWalletBase
|
|||
final lastOutput = updatedOutputs.last;
|
||||
final amountLeftForChange = amountLeftForChangeAndFee - fee;
|
||||
|
||||
if (!_isBelowDust(amountLeftForChange)) {
|
||||
if (_isBelowDust(amountLeftForChange)) {
|
||||
// If has change that is lower than dust, will end up with tx rejected by network rules
|
||||
// so remove the change amount
|
||||
updatedOutputs.removeLast();
|
||||
outputs.removeLast();
|
||||
|
||||
if (amountLeftForChange < 0) {
|
||||
if (!spendingAllCoins) {
|
||||
return estimateTxForAmount(
|
||||
credentialsAmount,
|
||||
outputs,
|
||||
updatedOutputs,
|
||||
feeRate,
|
||||
inputsCount: utxoDetails.utxos.length + 1,
|
||||
memo: memo,
|
||||
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
|
||||
hasSilentPayment: hasSilentPayment,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
} else {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
}
|
||||
}
|
||||
|
||||
return EstimatedTxResult(
|
||||
utxos: utxoDetails.utxos,
|
||||
inputPrivKeyInfos: utxoDetails.inputPrivKeyInfos,
|
||||
publicKeys: utxoDetails.publicKeys,
|
||||
fee: fee,
|
||||
amount: amount,
|
||||
hasChange: false,
|
||||
isSendAll: spendingAllCoins,
|
||||
memo: memo,
|
||||
spendsUnconfirmedTX: utxoDetails.spendsUnconfirmedTX,
|
||||
spendsSilentPayment: utxoDetails.spendsSilentPayment,
|
||||
);
|
||||
} else {
|
||||
// Here, lastOutput already is change, return the amount left without the fee to the user's address.
|
||||
updatedOutputs[updatedOutputs.length - 1] = BitcoinOutput(
|
||||
address: lastOutput.address,
|
||||
|
@ -740,75 +767,6 @@ abstract class ElectrumWalletBase
|
|||
isSilentPayment: lastOutput.isSilentPayment,
|
||||
isChange: true,
|
||||
);
|
||||
} else {
|
||||
// If has change that is lower than dust, will end up with tx rejected by network rules, so estimate again without the added change
|
||||
updatedOutputs.removeLast();
|
||||
outputs.removeLast();
|
||||
|
||||
// Still has inputs to spend before failing
|
||||
if (!spendingAllCoins) {
|
||||
return estimateTxForAmount(
|
||||
credentialsAmount,
|
||||
outputs,
|
||||
updatedOutputs,
|
||||
feeRate,
|
||||
inputsCount: utxoDetails.utxos.length + 1,
|
||||
memo: memo,
|
||||
hasSilentPayment: hasSilentPayment,
|
||||
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
}
|
||||
|
||||
final estimatedSendAll = await estimateSendAllTx(
|
||||
updatedOutputs,
|
||||
feeRate,
|
||||
memo: memo,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
|
||||
if (estimatedSendAll.amount == credentialsAmount) {
|
||||
return estimatedSendAll;
|
||||
}
|
||||
|
||||
// Estimate to user how much is needed to send to cover the fee
|
||||
final maxAmountWithReturningChange = utxoDetails.allInputsAmount - _dustAmount - fee - 1;
|
||||
throw BitcoinTransactionNoDustOnChangeException(
|
||||
BitcoinAmountUtils.bitcoinAmountToString(amount: maxAmountWithReturningChange),
|
||||
BitcoinAmountUtils.bitcoinAmountToString(amount: estimatedSendAll.amount),
|
||||
);
|
||||
}
|
||||
|
||||
// Attempting to send less than the dust limit
|
||||
if (_isBelowDust(amount)) {
|
||||
throw BitcoinTransactionNoDustException();
|
||||
}
|
||||
|
||||
final totalAmount = amount + fee;
|
||||
|
||||
if (totalAmount > (balance[currency]!.confirmed + balance[currency]!.secondConfirmed)) {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
}
|
||||
|
||||
if (totalAmount > utxoDetails.allInputsAmount) {
|
||||
if (spendingAllCoins) {
|
||||
throw BitcoinTransactionWrongBalanceException();
|
||||
} else {
|
||||
updatedOutputs.removeLast();
|
||||
outputs.removeLast();
|
||||
return estimateTxForAmount(
|
||||
credentialsAmount,
|
||||
outputs,
|
||||
updatedOutputs,
|
||||
feeRate,
|
||||
inputsCount: utxoDetails.utxos.length + 1,
|
||||
memo: memo,
|
||||
useUnconfirmed: useUnconfirmed ?? spendingAllConfirmedCoins,
|
||||
hasSilentPayment: hasSilentPayment,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return EstimatedTxResult(
|
||||
utxos: utxoDetails.utxos,
|
||||
|
@ -817,12 +775,14 @@ abstract class ElectrumWalletBase
|
|||
fee: fee,
|
||||
amount: amount,
|
||||
hasChange: true,
|
||||
isSendAll: false,
|
||||
isSendAll: spendingAllCoins,
|
||||
memo: memo,
|
||||
spendsUnconfirmedTX: utxoDetails.spendsUnconfirmedTX,
|
||||
spendsSilentPayment: utxoDetails.spendsSilentPayment,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> calcFee({
|
||||
required List<UtxoWithAddress> utxos,
|
||||
|
@ -895,15 +855,20 @@ abstract class ElectrumWalletBase
|
|||
: feeRate(transactionCredentials.priority!);
|
||||
|
||||
EstimatedTxResult estimatedTx;
|
||||
final updatedOutputs =
|
||||
outputs.map((e) => BitcoinOutput(address: e.address, value: e.value)).toList();
|
||||
final updatedOutputs = outputs
|
||||
.map((e) => BitcoinOutput(
|
||||
address: e.address,
|
||||
value: e.value,
|
||||
isSilentPayment: e.isSilentPayment,
|
||||
isChange: e.isChange,
|
||||
))
|
||||
.toList();
|
||||
|
||||
if (sendAll) {
|
||||
estimatedTx = await estimateSendAllTx(
|
||||
updatedOutputs,
|
||||
feeRateInt,
|
||||
memo: memo,
|
||||
credentialsAmount: credentialsAmount,
|
||||
hasSilentPayment: hasSilentPayment,
|
||||
coinTypeToSpendFrom: coinTypeToSpendFrom,
|
||||
);
|
||||
|
|
|
@ -109,12 +109,7 @@ PODS:
|
|||
- FlutterMacOS
|
||||
- permission_handler_apple (9.1.1):
|
||||
- Flutter
|
||||
- Protobuf (3.27.2)
|
||||
- ReachabilitySwift (5.2.3)
|
||||
- reactive_ble_mobile (0.0.1):
|
||||
- Flutter
|
||||
- Protobuf (~> 3.5)
|
||||
- SwiftProtobuf (~> 1.0)
|
||||
- SDWebImage (5.19.4):
|
||||
- SDWebImage/Core (= 5.19.4)
|
||||
- SDWebImage/Core (5.19.4)
|
||||
|
@ -132,6 +127,9 @@ PODS:
|
|||
- Toast (4.1.1)
|
||||
- uni_links (0.0.1):
|
||||
- Flutter
|
||||
- universal_ble (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
|
@ -161,12 +159,12 @@ DEPENDENCIES:
|
|||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- reactive_ble_mobile (from `.symlinks/plugins/reactive_ble_mobile/ios`)
|
||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sp_scanner (from `.symlinks/plugins/sp_scanner/ios`)
|
||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||
- universal_ble (from `.symlinks/plugins/universal_ble/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
- workmanager (from `.symlinks/plugins/workmanager/ios`)
|
||||
|
@ -178,7 +176,6 @@ SPEC REPOS:
|
|||
- DKPhotoGallery
|
||||
- MTBBarcodeScanner
|
||||
- OrderedSet
|
||||
- Protobuf
|
||||
- ReachabilitySwift
|
||||
- SDWebImage
|
||||
- SwiftProtobuf
|
||||
|
@ -226,8 +223,6 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
reactive_ble_mobile:
|
||||
:path: ".symlinks/plugins/reactive_ble_mobile/ios"
|
||||
sensitive_clipboard:
|
||||
:path: ".symlinks/plugins/sensitive_clipboard/ios"
|
||||
share_plus:
|
||||
|
@ -238,6 +233,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/sp_scanner/ios"
|
||||
uni_links:
|
||||
:path: ".symlinks/plugins/uni_links/ios"
|
||||
universal_ble:
|
||||
:path: ".symlinks/plugins/universal_ble/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock_plus:
|
||||
|
@ -271,9 +268,7 @@ SPEC CHECKSUMS:
|
|||
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||
Protobuf: fb2c13674723f76ff6eede14f78847a776455fa2
|
||||
ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979
|
||||
reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c
|
||||
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
|
||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||
|
@ -283,6 +278,7 @@ SPEC CHECKSUMS:
|
|||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||
|
|
|
@ -106,8 +106,7 @@ class AddressValidator extends TextValidator {
|
|||
case CryptoCurrency.wow:
|
||||
pattern = '[0-9a-zA-Z]+';
|
||||
case CryptoCurrency.bch:
|
||||
pattern =
|
||||
'(?!bitcoincash:)[0-9a-zA-Z]*|(?!bitcoincash:)q|p[0-9a-zA-Z]{41}|(?!bitcoincash:)q|p[0-9a-zA-Z]{42}|bitcoincash:q|p[0-9a-zA-Z]{41}|bitcoincash:q|p[0-9a-zA-Z]{42}';
|
||||
pattern = '^(bitcoincash:)?(q|p)[0-9a-zA-Z]{41,42}';
|
||||
case CryptoCurrency.bnb:
|
||||
pattern = '[0-9a-zA-Z]+';
|
||||
case CryptoCurrency.hbar:
|
||||
|
|
|
@ -141,8 +141,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
'coinTo': _normalizeCurrency(request.toCurrency),
|
||||
'networkFrom': _networkFor(request.fromCurrency),
|
||||
'networkTo': _networkFor(request.toCurrency),
|
||||
'withdrawalAddress': request.toAddress,
|
||||
'refundAddress': request.refundAddress,
|
||||
'withdrawalAddress': _normalizeAddress(request.toAddress),
|
||||
'refundAddress': _normalizeAddress(request.refundAddress),
|
||||
'rateType': _getRateType(isFixedRateMode),
|
||||
'apiToken': apiKey,
|
||||
};
|
||||
|
@ -275,4 +275,7 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeAddress(String address) =>
|
||||
address.startsWith('bitcoincash:') ? address.replaceFirst('bitcoincash:', '') : address;
|
||||
}
|
||||
|
|
|
@ -129,8 +129,8 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
"currency_to": _normalizeCurrency(request.toCurrency),
|
||||
"amount": request.fromAmount,
|
||||
"fixed": isFixedRateMode,
|
||||
"user_refund_address": request.refundAddress,
|
||||
"address_to": request.toAddress
|
||||
"user_refund_address": _normalizeAddress(request.refundAddress),
|
||||
"address_to": _normalizeAddress(request.toAddress)
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, createExchangePath, params);
|
||||
|
||||
|
@ -243,4 +243,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
return currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeAddress(String address) =>
|
||||
address.startsWith('bitcoincash:') ? address.replaceFirst('bitcoincash:', '') : address;
|
||||
}
|
||||
|
|
|
@ -129,8 +129,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
|||
if (isFixedRateMode) 'rate_id': rateId,
|
||||
'amount':
|
||||
isFixedRateMode ? double.parse(request.toAmount) : double.parse(request.fromAmount),
|
||||
'address': request.toAddress,
|
||||
'refund_address': request.refundAddress,
|
||||
'address': _normalizeAddress(request.toAddress),
|
||||
'refund_address': _normalizeAddress(request.refundAddress),
|
||||
'additional_fee_percent': _additionalFeePercent,
|
||||
};
|
||||
|
||||
|
@ -296,4 +296,7 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
|||
|
||||
return currency.tag!.toLowerCase();
|
||||
}
|
||||
|
||||
String _normalizeAddress(String address) =>
|
||||
address.startsWith('bitcoincash:') ? address.replaceFirst('bitcoincash:', '') : address;
|
||||
}
|
||||
|
|
|
@ -116,9 +116,7 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
|||
required bool isFixedRateMode,
|
||||
required bool isSendAll,
|
||||
}) async {
|
||||
String formattedToAddress = request.toAddress.startsWith('bitcoincash:')
|
||||
? request.toAddress.replaceFirst('bitcoincash:', '')
|
||||
: request.toAddress;
|
||||
|
||||
|
||||
final formattedFromAmount = double.parse(request.fromAmount);
|
||||
|
||||
|
@ -126,11 +124,11 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
|||
'from_asset': _normalizeCurrency(request.fromCurrency),
|
||||
'to_asset': _normalizeCurrency(request.toCurrency),
|
||||
'amount': _doubleToThorChainString(formattedFromAmount),
|
||||
'destination': formattedToAddress,
|
||||
'destination': _normalizeAddress(request.toAddress),
|
||||
'affiliate': _affiliateName,
|
||||
'affiliate_bps': _affiliateBps,
|
||||
'refund_address':
|
||||
isRefundAddressSupported.contains(request.fromCurrency) ? request.refundAddress : '',
|
||||
isRefundAddressSupported.contains(request.fromCurrency) ? _normalizeAddress(request.refundAddress) : '',
|
||||
};
|
||||
|
||||
final responseJSON = await _getSwapQuote(params);
|
||||
|
@ -288,4 +286,7 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
|||
|
||||
return currentState;
|
||||
}
|
||||
|
||||
String _normalizeAddress(String address) =>
|
||||
address.startsWith('bitcoincash:') ? address.replaceFirst('bitcoincash:', '') : address;
|
||||
}
|
||||
|
|
|
@ -99,18 +99,23 @@ abstract class ContactListViewModelBase with Store {
|
|||
|
||||
Future<void> delete(ContactRecord contact) async => contact.original.delete();
|
||||
|
||||
@computed
|
||||
List<ContactRecord> get contactsToShow =>
|
||||
contacts.where((element) => _isValidForCurrency(element)).toList();
|
||||
ObservableList<ContactRecord> get contactsToShow =>
|
||||
ObservableList.of(contacts.where((element) => _isValidForCurrency(element)));
|
||||
|
||||
@computed
|
||||
List<WalletContact> get walletContactsToShow =>
|
||||
walletContacts.where((element) => _isValidForCurrency(element)).toList();
|
||||
|
||||
bool _isValidForCurrency(ContactBase element) {
|
||||
if (element.name.contains('Silent Payments')) return false;
|
||||
if (element.name.contains('MWEB')) return false;
|
||||
|
||||
return _currency == null ||
|
||||
element.type == _currency ||
|
||||
element.type.title == _currency!.tag ||
|
||||
element.type.tag == _currency!.tag;
|
||||
(element.type.tag != null &&
|
||||
_currency?.tag != null &&
|
||||
element.type.tag == _currency?.tag) ||
|
||||
_currency?.toString() == element.type.tag ||
|
||||
_currency?.tag == element.type.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -482,18 +482,18 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
nano!.updateTransactions(wallet);
|
||||
}
|
||||
|
||||
|
||||
if (pendingTransaction!.id.isNotEmpty) {
|
||||
|
||||
final descriptionKey = '${pendingTransaction!.id}_${wallet.walletAddresses.primaryAddress}';
|
||||
_settingsStore.shouldSaveRecipientAddress
|
||||
? await transactionDescriptionBox.add(TransactionDescription(
|
||||
id: descriptionKey,
|
||||
recipientAddress: address,
|
||||
transactionNote: note))
|
||||
transactionNote: note,
|
||||
))
|
||||
: await transactionDescriptionBox.add(TransactionDescription(
|
||||
id: descriptionKey,
|
||||
transactionNote: note));
|
||||
transactionNote: note,
|
||||
));
|
||||
}
|
||||
|
||||
state = TransactionCommitted();
|
||||
|
|
Loading…
Reference in a new issue