Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(EWM-313): simulate transaction tree #547

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -571,5 +571,22 @@
"invalidReceiverAddress": "Invalid receiver address",
"deleteBookmarksQuestion": "Are you sure you want\nto delete all bookmarks?",
"deleteBookmarksDescription": "All bookmarks will be permanently deleted",
"save": "Save"
"save": "Save",
"txTreeSimulationErrorComputePhase": {
"0": "Execution failed on ",
"1": " with exit code {}."
},
"txTreeSimulationErrorActionPhase": {
"0": "Action phase failed on ",
"1": " with exit code {}."
},
"txTreeSimulationErrorFrozen": {
"0": "Account ",
"1": " will be frozen due to storage fee debt."
},
"txTreeSimulationErrorDeleted": {
"0": "Account ",
"1": " will be deleted due to storage fee debt."
},
"txTreeSimulationErrorHint": "Please contact technical support."
}
19 changes: 18 additions & 1 deletion assets/translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -571,5 +571,22 @@
"invalidReceiverAddress": "Invalid receiver address",
"deleteBookmarksQuestion": "Are you sure you want\nto delete all bookmarks?",
"deleteBookmarksDescription": "All bookmarks will be permanently deleted",
"save": "Save"
"save": "Save",
"txTreeSimulationErrorComputePhase": {
"0": "Execution failed on ",
"1": " with exit code {}."
},
"txTreeSimulationErrorActionPhase": {
"0": "Action phase failed on ",
"1": " with exit code {}."
},
"txTreeSimulationErrorFrozen": {
"0": "Account ",
"1": " will be frozen due to storage fee debt."
},
"txTreeSimulationErrorDeleted": {
"0": "Account ",
"1": " will be deleted due to storage fee debt."
},
"txTreeSimulationErrorHint": "Please contact technical support."
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import 'package:app/app/service/service.dart';
import 'package:app/utils/constants.dart';
import 'package:app/utils/utils.dart';
import 'package:collection/collection.dart';
import 'package:elementary/elementary.dart';
import 'package:nekoton_repository/nekoton_repository.dart';
import 'package:flutter/material.dart';
import 'package:nekoton_repository/nekoton_repository.dart' hide Message;
import 'package:rxdart/rxdart.dart';

class SendMessageModel extends ElementaryModel {
SendMessageModel(
ErrorHandler errorHandler,
this._nekotonRepository,
this._messengerService,
) : super(errorHandler: errorHandler);

final NekotonRepository _nekotonRepository;
final MessengerService _messengerService;

TransportStrategy get transport => _nekotonRepository.currentTransport;

Expand All @@ -32,43 +36,50 @@ class SendMessageModel extends ElementaryModel {
Future<List<PublicKey>?> getLocalCustodiansAsync(Address address) =>
_nekotonRepository.getLocalCustodiansAsync(address);

Future<BigInt> estimateFees({
Future<UnsignedMessage> prepareTransfer({
required Address address,
required Address destination,
required PublicKey? publicKey,
required BigInt amount,
required FunctionCall? payload,
required bool bounce,
}) async {
UnsignedMessage? message;
final body = await payload?.let(
(value) => encodeInternalInput(
contractAbi: payload.abi,
method: payload.method,
input: payload.params,
),
);

try {
final body = await payload?.let(
(value) => encodeInternalInput(
contractAbi: payload.abi,
method: payload.method,
input: payload.params,
),
);
return _nekotonRepository.prepareTransfer(
address: address,
publicKey: publicKey,
destination: destination,
amount: amount,
body: body,
bounce: bounce,
expiration: defaultSendTimeout,
);
}

message = await _nekotonRepository.prepareTransfer(
Future<BigInt> estimateFees({
required Address address,
required UnsignedMessage message,
}) =>
_nekotonRepository.estimateFees(
address: address,
publicKey: publicKey,
destination: destination,
amount: amount,
body: body,
bounce: bounce,
expiration: defaultSendTimeout,
message: message,
);

return await _nekotonRepository.estimateFees(
Future<List<TxTreeSimulationErrorItem>> simulateTransactionTree({
required Address address,
required UnsignedMessage message,
}) =>
_nekotonRepository.simulateTransactionTree(
address: address,
message: message,
);
} finally {
message?.dispose();
}
}

String? getSeedName(PublicKey custodian) =>
_nekotonRepository.seedList.findSeedKey(custodian)?.name;
Expand All @@ -82,4 +93,13 @@ class SendMessageModel extends ElementaryModel {

return (details.item1, details.item2);
}

void showError(BuildContext context, String message) {
_messengerService.show(
Message.error(
context: context,
message: message,
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:app/feature/profile/profile.dart';
import 'package:app/feature/wallet/wallet.dart';
import 'package:app/generated/generated.dart';
import 'package:app/utils/utils.dart';
import 'package:app/widgets/widgets.dart';
import 'package:elementary/elementary.dart';
import 'package:elementary_helper/elementary_helper.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -132,10 +133,21 @@ class SendMessageWidget extends ElementaryWidget<SendMessageWidgetModel> {
),
),
if (wm.account != null)
EnterPasswordWidgetV2(
publicKey: wm.account!.publicKey,
title: LocaleKeys.sendWord.tr(),
onPasswordEntered: wm.onSubmit,
DoubleSourceBuilder(
firstSource: wm.isLoading,
secondSource: wm.txErrors,
builder: (_, isLoading, txErrors) {
if (txErrors?.isNotEmpty ?? false) {
return TxTreeSimulationErrorWidget(txErrors: txErrors!);
}

return EnterPasswordWidgetV2(
isLoading: isLoading,
publicKey: wm.account!.publicKey,
title: LocaleKeys.sendWord.tr(),
onPasswordEntered: wm.onSubmit,
);
},
),
],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:app/core/wm/custom_wm.dart';
import 'package:app/di/di.dart';
import 'package:app/feature/browser/approvals_listener/actions/send_message/send_message_model.dart';
import 'package:app/feature/browser/approvals_listener/actions/send_message/send_message_widget.dart';
import 'package:app/utils/utils.dart';
import 'package:elementary_helper/elementary_helper.dart';
import 'package:flutter/material.dart';
import 'package:nekoton_repository/nekoton_repository.dart';
Expand All @@ -30,6 +31,7 @@ SendMessageWidgetModel defaultSendMessageWidgetModelFactory(
SendMessageModel(
createPrimaryErrorHandler(context),
inject(),
inject(),
),
);

Expand All @@ -42,9 +44,11 @@ class SendMessageWidgetModel
late final _data = createNotifier<TransferData>();
late final _fee = createNotifier<BigInt>();
late final _feeError = createNotifier<String>();
late final _txErrors = createNotifier<List<TxTreeSimulationErrorItem>>();
late final _publicKey = createNotifier(account?.publicKey);
late final _custodians = createNotifier<List<PublicKey>>();
late final _balance = createNotifier<Money>();
late final _isLoading = createNotifier(false);
late final StreamSubscription<Money> _subscription;

ListenableState<TransferData> get data => _data;
Expand All @@ -53,12 +57,16 @@ class SendMessageWidgetModel

ListenableState<String> get feeError => _feeError;

ListenableState<List<TxTreeSimulationErrorItem>> get txErrors => _txErrors;

ListenableState<PublicKey> get publicKey => _publicKey;

ListenableState<List<PublicKey>> get custodians => _custodians;

ListenableState<Money?> get balance => _balance;

ListenableState<bool> get isLoading => _isLoading;

Currency get nativeCurrency =>
Currencies()[model.transport.nativeTokenTicker]!;

Expand Down Expand Up @@ -87,7 +95,7 @@ class SendMessageWidgetModel
model.getBalanceStream(widget.sender).listen(_balance.accept);

_getCustodians();
_estimateFees();
_prepareTransfer();
}

@override
Expand Down Expand Up @@ -128,9 +136,11 @@ class SendMessageWidgetModel
_custodians.accept(custodians);
}

Future<void> _estimateFees() async {
Future<void> _prepareTransfer() async {
UnsignedMessage? message;

try {
final fee = await model.estimateFees(
message = await model.prepareTransfer(
address: widget.sender,
destination: widget.recipient,
publicKey: account?.publicKey,
Expand All @@ -139,11 +149,40 @@ class SendMessageWidgetModel
bounce: widget.bounce,
);

await _estimateFees(message);
await _simulateTransactionTree(message);
} finally {
message?.dispose();
}
}

Future<void> _estimateFees(UnsignedMessage message) async {
try {
final fee = await model.estimateFees(
address: widget.sender,
message: message,
);

_fee.accept(fee);
} on FfiException catch (e) {
_feeError.accept(e.message);
} on Exception catch (e) {
_feeError.accept(e.toString());
}
}

Future<void> _simulateTransactionTree(UnsignedMessage message) async {
try {
final fee = await model.simulateTransactionTree(
address: widget.sender,
message: message,
);

_txErrors.accept(fee);
} catch (e) {
contextSafe?.let(
(context) => model.showError(context, e.toString()),
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class TokenWalletSendBloc
late UnsignedMessage unsignedMessage;
UnsignedMessage? _unsignedMessage;

List<TxTreeSimulationErrorItem>? txErrors;

TransportStrategy get transport => nekotonRepository.currentTransport;

Currency get currency => Currencies()[transport.nativeTokenTicker]!;
Expand Down Expand Up @@ -143,6 +145,10 @@ class TokenWalletSendBloc
address: owner,
message: unsignedMessage,
);
txErrors = await nekotonRepository.simulateTransactionTree(
address: owner,
message: unsignedMessage,
);

final walletState = await nekotonRepository.walletsStream
.expand((e) => e)
Expand Down Expand Up @@ -170,7 +176,7 @@ class TokenWalletSendBloc
return;
}

emit(TokenWalletSendState.readyToSend(fees!, sendAmount));
emit(TokenWalletSendState.readyToSend(fees!, sendAmount, txErrors));
} on FfiException catch (e, t) {
_logger.severe('_handleSend', e, t);
emit(TokenWalletSendState.calculatingError(e.message));
Expand Down Expand Up @@ -226,12 +232,12 @@ class TokenWalletSendBloc
message: e.message,
),
);
emit(TokenWalletSendState.readyToSend(fees!, sendAmount));
emit(TokenWalletSendState.readyToSend(fees!, sendAmount, txErrors));
} on Exception catch (e, t) {
_logger.severe('_handleSend', e, t);
messengerService
.show(Message.error(context: context, message: e.toString()));
emit(TokenWalletSendState.readyToSend(fees!, sendAmount));
emit(TokenWalletSendState.readyToSend(fees!, sendAmount, txErrors));
}
}

Expand Down
Loading
Loading