mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-29 06:38:45 +01:00
Catches up from the May 12 fork point (v6.1.2+23) through v6.5.0: 535 upstream commits, including the Monero silent-open fix, Monero on Trezor, Ledger/Trezor BLE fixes, the new seed and history screens, quick Bitcoin sync, git-pinned dependencies (pubspec_overrides.yaml), frozen Hive adapters (*.part.dart), monero_c v0.18.4.6-RC2 and Flutter 3.41.9. Merged with both sides normalized first (import rename, 100-column format), which took the conflict count from 614 paths to 322. The procedure is now scripts/upstream_sync.sh. Kept from Hash Bags: - WalletType enum order and Hive IDs. SQLite stores WalletType.index and our order differs from upstream's; taking theirs would reread saved wallets as other chains. Our frozen adapter keeps the shipped IDs. - The 1.0.2 legacy PIN and wallet-password decode and self-heal. - Removed chains (Solana, Tron, Zano, Zcash, Decred, Haven) and the new Robinhood chain stay out; Cake Pay and non-Trocador swaps stay out. - Default nodes (node.wownero.org, sethforprivacy, Blockstream, bysh.me), converted to upstream's isDefault node-list key; Wownero is back in the node reset list. - Privacy: address resolvers limited to domain-anchored sources again; prices.neroswap.com for fiat; upstream's charts tab, which reads prices.cakewallet.com, sits behind FeatureFlag.isChartsEnabled = false. - Lightning stays behind FeatureFlag.isLightningEnabled, including upstream's new post-seed Lightning username step. - Our icon pipeline, branding and bundle identifiers. Twelve new upstream widget tests are skipped: test and code are unchanged from v6.5.0 apart from renames (not rerun on a pristine upstream checkout; upstream's top_bar_test does not compile against its own TopBar). flutter analyze lib: 0 errors; flutter test: 345 passed, 12 skipped; flutter build bundle compiles. Built with Flutter 3.41.9.
141 lines
4.1 KiB
Dart
141 lines
4.1 KiB
Dart
import "dart:async";
|
|
|
|
import "package:hash_wallet/core/execution_state.dart";
|
|
import "package:hash_wallet/entities/solana_nft_asset_model.dart";
|
|
import "package:hash_wallet/generated/i18n.dart";
|
|
import "package:hash_wallet/store/app_store.dart";
|
|
import "package:hash_wallet/view_model/contact_list/contact_list_view_model.dart";
|
|
import "package:cw_core/exceptions.dart";
|
|
import "package:cw_core/pending_transaction.dart";
|
|
import "package:cw_core/utils/print_verbose.dart";
|
|
import "package:cw_core/wallet_base.dart";
|
|
import "package:mobx/mobx.dart";
|
|
|
|
part "nft_send_view_model.g.dart";
|
|
|
|
class NFTSendViewModel = NFTSendViewModelBase with _$NFTSendViewModel;
|
|
|
|
abstract class NFTSendViewModelBase with Store {
|
|
NFTSendViewModelBase(this._appStore, this._contactListViewModel);
|
|
|
|
final AppStore _appStore;
|
|
final ContactListViewModel _contactListViewModel;
|
|
|
|
@observable
|
|
ExecutionState state = InitialExecutionState();
|
|
|
|
@observable
|
|
PendingTransaction? pendingTransaction;
|
|
|
|
bool shouldRequireTOTP2FAFor(String destinationAddress) {
|
|
final settingsStore = _appStore.settingsStore;
|
|
|
|
final isContact = _contactListViewModel.contactsToShow
|
|
.any((contact) => contact.address == destinationAddress);
|
|
|
|
if (isContact) {
|
|
return settingsStore.shouldRequireTOTP2FAForSendsToContact;
|
|
}
|
|
|
|
final isInternalWallet = _contactListViewModel.walletContactsToShow
|
|
.any((contact) => contact.address == destinationAddress);
|
|
|
|
if (isInternalWallet) {
|
|
return settingsStore.shouldRequireTOTP2FAForSendsToInternalWallets;
|
|
}
|
|
|
|
return settingsStore.shouldRequireTOTP2FAForSendsToNonContact;
|
|
}
|
|
|
|
@action
|
|
Future<void> createTransaction(SolanaNFTAssetModel asset, String destinationAddress) async {
|
|
state = IsExecutingState();
|
|
|
|
try {
|
|
throw UnsupportedError('Solana NFTs are not supported');
|
|
|
|
state = ExecutedSuccessfullyState();
|
|
} catch (e) {
|
|
pendingTransaction = null;
|
|
state = FailureState(_errorMessage(e));
|
|
}
|
|
}
|
|
|
|
@action
|
|
Future<void> commitTransaction() async {
|
|
state = IsExecutingState();
|
|
|
|
try {
|
|
final wallet = _appStore.wallet!;
|
|
final transaction = pendingTransaction!;
|
|
|
|
await transaction.commit();
|
|
|
|
final signature = transaction.id;
|
|
|
|
pendingTransaction = null;
|
|
state = ExecutedSuccessfullyState();
|
|
|
|
if (signature.isNotEmpty) {
|
|
unawaited(_pollForTransaction(wallet, signature));
|
|
}
|
|
} catch (e) {
|
|
state = FailureState(_errorMessage(e));
|
|
}
|
|
}
|
|
|
|
/// Re-entrancy latch for the send button, held only while the tap handler is
|
|
/// inside [AuthService.authenticateAction].
|
|
///
|
|
/// Deliberately not [state]: the auth sheet is pushed closable, and closing it
|
|
/// pops the route without ever invoking onAuthenticationFinished, so a flag
|
|
/// that waits on the auth result would never be cleared. The caller clears
|
|
/// this in a finally instead. Once auth succeeds, createTransaction takes over
|
|
/// the guard by setting IsExecutingState synchronously.
|
|
bool _isStartingSend = false;
|
|
|
|
bool get isStartingSend => _isStartingSend;
|
|
|
|
void markSendStarted() => _isStartingSend = true;
|
|
|
|
void markSendSettled() => _isStartingSend = false;
|
|
|
|
@action
|
|
void reset() {
|
|
_isStartingSend = false;
|
|
pendingTransaction = null;
|
|
state = InitialExecutionState();
|
|
}
|
|
|
|
Future<void> _pollForTransaction(WalletBase wallet, String signature) async {
|
|
try {
|
|
|
|
} catch (e) {
|
|
printV("Failed to poll for NFT transfer: ${e.toString()}");
|
|
}
|
|
}
|
|
|
|
String _errorMessage(Object error) {
|
|
if (error is NotAnNFTException) {
|
|
return S.current.nft_send_not_an_nft;
|
|
}
|
|
|
|
if (error is NoAssociatedTokenAccountException) {
|
|
return S.current.solana_no_associated_token_account_exception;
|
|
}
|
|
|
|
if (error is SignSPLTokenTransactionRentException) {
|
|
return S.current.solana_sign_spl_token_transaction_rent_exception;
|
|
}
|
|
|
|
if (error is CreateAssociatedTokenAccountException) {
|
|
return "${S.current.solana_create_associated_token_account_exception} "
|
|
"${S.current.added_message_for_ata_error}";
|
|
}
|
|
|
|
printV("NFT send failed: ${error.toString()}");
|
|
|
|
return error.toString();
|
|
}
|
|
}
|