mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
- Monero sync patches - Trezor bitcoin - Solana NFTs sending - Bug fixes
147 lines
4.3 KiB
Dart
147 lines
4.3 KiB
Dart
import "dart:async";
|
|
|
|
import "package:cake_wallet/core/execution_state.dart";
|
|
import "package:cake_wallet/entities/solana_nft_asset_model.dart";
|
|
import "package:cake_wallet/generated/i18n.dart";
|
|
import "package:cake_wallet/solana/solana.dart";
|
|
import "package:cake_wallet/store/app_store.dart";
|
|
import "package:cake_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 {
|
|
pendingTransaction = await solana!.sendNFT(
|
|
_appStore.wallet!,
|
|
mintAddress: asset.mint!,
|
|
destinationAddress: destinationAddress,
|
|
name: asset.name,
|
|
);
|
|
|
|
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 {
|
|
await solana!.pollForTransaction(wallet, signature);
|
|
} 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();
|
|
}
|
|
}
|