CAKE-345 | changed bitcoin transaction credentials; reworked createTransaction() method in the electrum_wallet.dart for batch sending; fixed exchange_trade_page.dart and send_page.dart; reworked confirm_sending_alert.dart; fixed _credenials() and commitTransaction() methods in the send_view_model.dart
OleksandrSobol committed
Jul 20, 2021 at 18:03 UTC
7b2d89f96f79e7156979eb6614a8fc1a2c038f6c
20 files changed
+377
-234
lib/bitcoin/bitcoin_transaction_credentials.dart
+3
-3
@@ -1,9 +1,9 @@
1
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2
+import 'package:cake_wallet/view_model/send/send_item.dart';
3
4
class BitcoinTransactionCredentials {
4
- BitcoinTransactionCredentials(this.address, this.amount, this.priority);
5
+ BitcoinTransactionCredentials(this.sendItemList, this.priority);
6
6
- final String address;
7
- final String amount;
7
+ final List<SendItem> sendItemList;
8
BitcoinTransactionPriority priority;
9
}
lib/bitcoin/electrum_wallet.dart
+75
-24
@@ -218,20 +218,71 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
218
const minAmount = 546;
219
final transactionCredentials = credentials as BitcoinTransactionCredentials;
220
final inputs = <BitcoinUnspent>[];
221
+ final sendItemList = transactionCredentials.sendItemList;
222
final allAmountFee =
223
calculateEstimatedFee(transactionCredentials.priority, null);
224
final allAmount = balance.confirmed - allAmountFee;
225
+ var credentialsAmount = 0;
226
+ var amount = 0;
227
var fee = 0;
225
- final credentialsAmount = transactionCredentials.amount != null
226
- ? stringDoubleToBitcoinAmount(transactionCredentials.amount)
227
- : 0;
228
- final amount = transactionCredentials.amount == null ||
229
- allAmount - credentialsAmount < minAmount
230
- ? allAmount
231
- : credentialsAmount;
228
+
229
+ if (sendItemList.length > 1) {
230
+ final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
231
+
232
+ if (sendAllItems?.isNotEmpty ?? false) {
233
+ throw BitcoinTransactionWrongBalanceException();
234
+ }
235
+
236
+ final nullAmountItems = sendItemList.where((item) =>
237
+ stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.')) <= 0)
238
+ .toList();
239
+
240
+ if (nullAmountItems?.isNotEmpty ?? false) {
241
+ throw BitcoinTransactionWrongBalanceException();
242
+ }
243
+
244
+ credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
245
+ previousValue + stringDoubleToBitcoinAmount(
246
+ element.cryptoAmount.replaceAll(',', '.')));
247
+
248
+ amount = allAmount - credentialsAmount < minAmount
249
+ ? allAmount
250
+ : credentialsAmount;
251
+
252
+ fee = amount == allAmount
253
+ ? allAmountFee
254
+ : calculateEstimatedFee(transactionCredentials.priority, amount,
255
+ outputsCount: sendItemList.length + 1);
256
+ } else {
257
+ final sendItem = sendItemList.first;
258
+
259
+ credentialsAmount = !sendItem.sendAll
260
+ ? stringDoubleToBitcoinAmount(
261
+ sendItem.cryptoAmount.replaceAll(',', '.'))
262
+ : 0;
263
+
264
+ amount = sendItem.sendAll || allAmount - credentialsAmount < minAmount
265
+ ? allAmount
266
+ : credentialsAmount;
267
+
268
+ fee = sendItem.sendAll || amount == allAmount
269
+ ? allAmountFee
270
+ : calculateEstimatedFee(transactionCredentials.priority, amount);
271
+ }
272
+
273
+ if (fee == 0) {
274
+ throw BitcoinTransactionWrongBalanceException();
275
+ }
276
+
277
+ final totalAmount = amount + fee;
278
+
279
+ if (totalAmount > balance.confirmed) {
280
+ throw BitcoinTransactionWrongBalanceException();
281
+ }
282
+
283
final txb = bitcoin.TransactionBuilder(network: networkType);
284
final changeAddress = address;
234
- var leftAmount = amount;
285
+ var leftAmount = totalAmount;
286
var totalInputAmount = 0;
287
288
if (_unspent.isEmpty) {
@@ -252,16 +303,6 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
303
throw BitcoinTransactionNoInputsException();
304
}
305
255
- final totalAmount = amount + fee;
256
- fee = transactionCredentials.amount != null
257
- ? feeAmountForPriority(transactionCredentials.priority, inputs.length,
258
- amount == allAmount ? 1 : 2)
259
- : allAmountFee;
260
-
261
- if (totalAmount > balance.confirmed) {
262
- throw BitcoinTransactionWrongBalanceException();
263
- }
264
-
306
if (amount <= 0 || totalInputAmount < amount) {
307
throw BitcoinTransactionWrongBalanceException();
308
}
@@ -282,11 +323,18 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
323
}
324
});
325
285
- txb.addOutput(
286
- addressToOutputScript(transactionCredentials.address, networkType),
287
- amount);
326
+ sendItemList.forEach((item) {
327
+ final _amount = item.sendAll
328
+ ? amount
329
+ : stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.'));
330
289
- final estimatedSize = estimatedTransactionSize(inputs.length, 2);
331
+ txb.addOutput(
332
+ addressToOutputScript(item.address, networkType),
333
+ _amount);
334
+ });
335
+
336
+ final estimatedSize =
337
+ estimatedTransactionSize(inputs.length, sendItemList.length + 1);
338
final feeAmount = feeRate(transactionCredentials.priority) * estimatedSize;
339
final changeValue = totalInputAmount - amount - feeAmount;
340
@@ -331,7 +379,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
379
feeRate(priority) * estimatedTransactionSize(inputsCount, outputsCount);
380
381
@override
334
- int calculateEstimatedFee(TransactionPriority priority, int amount) {
382
+ int calculateEstimatedFee(TransactionPriority priority, int amount,
383
+ {int outputsCount}) {
384
if (priority is BitcoinTransactionPriority) {
385
int inputsCount = 0;
386
@@ -350,8 +399,10 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
399
inputsCount = _unspent.length;
400
}
401
// If send all, then we have no change value
402
+ final _outputsCount = outputsCount ?? (amount != null ? 2 : 1);
403
+
404
return feeAmountForPriority(
354
- priority, inputsCount, amount != null ? 2 : 1);
405
+ priority, inputsCount, _outputsCount);
406
}
407
408
return 0;
lib/src/screens/exchange_trade/exchange_trade_page.dart
+2
-5
@@ -262,9 +262,6 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
262
263
if (state is ExecutedSuccessfullyState) {
264
WidgetsBinding.instance.addPostFrameCallback((_) {
265
- final item = widget.exchangeTradeViewModel.sendViewModel
266
- .sendItemList.first;
267
-
265
showPopUp<void>(
266
context: context,
267
builder: (BuildContext context) {
@@ -388,8 +385,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
385
.pendingTransactionFiatAmount +
386
' ' +
387
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
391
- recipientTitle: S.of(context).recipient_address,
392
- recipientAddress: item.address);
388
+ sendItemList: widget.exchangeTradeViewModel.sendViewModel
389
+ .sendItemList);
390
});
391
});
392
}
lib/src/screens/send/send_page.dart
+55
-50
@@ -266,56 +266,49 @@ class SendPage extends BasePage {
266
EdgeInsets.only(left: 24, right: 24, bottom: 24),
267
bottomSection: Column(
268
children: [
269
- PrimaryButton(
270
- onPressed: () {
271
- sendViewModel.addSendItem();
272
- },
273
- text: 'Add receiver',
274
- color: Colors.green,
275
- textColor: Colors.white,
269
+ if (sendViewModel.isAddReceiverButtonEnabled) Padding(
270
+ padding: EdgeInsets.only(bottom: 12),
271
+ child: PrimaryButton(
272
+ onPressed: () {
273
+ sendViewModel.addSendItem();
274
+ },
275
+ text: S.of(context).add_receiver,
276
+ color: Colors.green,
277
+ textColor: Colors.white,
278
+ )
279
),
277
- Padding(
278
- padding: EdgeInsets.only(top: 12),
279
- child: Observer(builder: (_) {
280
- return LoadingPrimaryButton(
281
- onPressed: () async {
282
- if (_formKey.currentState.validate()) {
283
- //await sendViewModel.createTransaction();
284
- // FIXME: for test only
285
- sendViewModel.clearSendItemList();
286
- await showPopUp<void>(
287
- context: context,
288
- builder: (BuildContext context) {
289
- return AlertWithOneAction(
290
- alertTitle: S.of(context).send,
291
- alertContent: S.of(context).send_success(
292
- sendViewModel.currency
293
- .toString()),
294
- buttonText: S.of(context).ok,
295
- buttonAction: () => Navigator.of(context).pop());
296
- });
297
- } else {
298
- await showPopUp<void>(
299
- context: context,
300
- builder: (BuildContext context) {
301
- return AlertWithOneAction(
302
- alertTitle: S.of(context).error,
303
- alertContent: 'Please, check your receivers forms',
304
- buttonText: S.of(context).ok,
305
- buttonAction: () =>
306
- Navigator.of(context).pop());
307
- });
308
- }
309
- },
310
- text: S.of(context).send,
311
- color: Theme.of(context).accentTextTheme.body2.color,
312
- textColor: Colors.white,
313
- isLoading: sendViewModel.state is IsExecutingState ||
314
- sendViewModel.state is TransactionCommitting,
315
- isDisabled: !sendViewModel.isReadyForSend,
316
- );
280
+ Observer(builder: (_) {
281
+ return LoadingPrimaryButton(
282
+ onPressed: () async {
283
+ if (!_formKey.currentState.validate()) {
284
+ if (sendViewModel.sendItemList.length > 1) {
285
+ showErrorValidationAlert(context);
286
+ }
287
+
288
+ return;
289
+ }
290
+
291
+ final notValidItems = sendViewModel.sendItemList
292
+ .where((item) =>
293
+ item.address.isEmpty || item.cryptoAmount.isEmpty)
294
+ .toList();
295
+
296
+ if (notValidItems?.isNotEmpty ?? false) {
297
+ showErrorValidationAlert(context);
298
+ return;
299
+ }
300
+
301
+ await sendViewModel.createTransaction();
302
},
318
- ))
303
+ text: S.of(context).send,
304
+ color: Theme.of(context).accentTextTheme.body2.color,
305
+ textColor: Colors.white,
306
+ isLoading: sendViewModel.state is IsExecutingState ||
307
+ sendViewModel.state is TransactionCommitting,
308
+ isDisabled: !sendViewModel.isReadyForSend,
309
+ );
310
+ },
311
+ )
312
],
313
)),
314
);
@@ -357,8 +350,7 @@ class SendPage extends BasePage {
350
feeValue: sendViewModel.pendingTransaction.feeFormatted,
351
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmount
352
+ ' ' + sendViewModel.fiat.title,
360
- recipientTitle: S.of(context).recipient_address,
361
- recipientAddress: '', // FIXME: sendViewModel.address,
353
+ sendItemList: sendViewModel.sendItemList,
354
rightButtonText: S.of(context).ok,
355
leftButtonText: S.of(context).cancel,
356
actionRightButton: () {
@@ -408,4 +400,17 @@ class SendPage extends BasePage {
400
final itemCount = controller.page.round();
401
return sendViewModel.sendItemList[itemCount];
402
}
403
+
404
+ void showErrorValidationAlert(BuildContext context) async {
405
+ await showPopUp<void>(
406
+ context: context,
407
+ builder: (BuildContext context) {
408
+ return AlertWithOneAction(
409
+ alertTitle: S.of(context).error,
410
+ alertContent: 'Please, check receiver forms',
411
+ buttonText: S.of(context).ok,
412
+ buttonAction: () =>
413
+ Navigator.of(context).pop());
414
+ });
415
+ }
416
}
lib/src/screens/send/widgets/confirm_sending_alert.dart
+165
-103
@@ -1,6 +1,8 @@
1
import 'package:cake_wallet/palette.dart';
2
+import 'package:cake_wallet/view_model/send/send_item.dart';
3
import 'package:flutter/material.dart';
4
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
5
+import 'package:cake_wallet/generated/i18n.dart';
6
7
class ConfirmSendingAlert extends BaseAlertDialog {
8
ConfirmSendingAlert({
@@ -11,14 +13,18 @@ class ConfirmSendingAlert extends BaseAlertDialog {
13
@required this.fee,
14
@required this.feeValue,
15
@required this.feeFiatAmount,
14
- @required this.recipientTitle,
15
- @required this.recipientAddress,
16
+ @required this.sendItemList,
17
@required this.leftButtonText,
18
@required this.rightButtonText,
19
@required this.actionLeftButton,
20
@required this.actionRightButton,
21
this.alertBarrierDismissible = true
21
- });
22
+ }) {
23
+ itemCount = sendItemList.length;
24
+ recipientTitle = itemCount > 1
25
+ ? S.current.transaction_details_recipient_address
26
+ : S.current.recipient_address;
27
+ }
28
29
final String alertTitle;
30
final String amount;
@@ -27,14 +33,16 @@ class ConfirmSendingAlert extends BaseAlertDialog {
33
final String fee;
34
final String feeValue;
35
final String feeFiatAmount;
30
- final String recipientTitle;
31
- final String recipientAddress;
36
+ final List<SendItem> sendItemList;
37
final String leftButtonText;
38
final String rightButtonText;
39
final VoidCallback actionLeftButton;
40
final VoidCallback actionRightButton;
41
final bool alertBarrierDismissible;
42
43
+ String recipientTitle;
44
+ int itemCount;
45
+
46
@override
47
String get titleText => alertTitle;
48
@@ -58,127 +66,181 @@ class ConfirmSendingAlert extends BaseAlertDialog {
66
67
@override
68
Widget content(BuildContext context) {
61
- return Column(
62
- children: <Widget>[
63
- Row(
64
- mainAxisSize: MainAxisSize.max,
65
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
66
- crossAxisAlignment: CrossAxisAlignment.start,
69
+ return Container(
70
+ height: 200,
71
+ child: SingleChildScrollView(
72
+ child: Column(
73
children: <Widget>[
68
- Text(
69
- amount,
70
- style: TextStyle(
71
- fontSize: 16,
72
- fontWeight: FontWeight.normal,
73
- fontFamily: 'Lato',
74
- color: Theme.of(context).primaryTextTheme.title.color,
75
- decoration: TextDecoration.none,
76
- ),
77
- ),
78
- Column(
79
- crossAxisAlignment: CrossAxisAlignment.end,
80
- children: [
74
+ Row(
75
+ mainAxisSize: MainAxisSize.max,
76
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
77
+ crossAxisAlignment: CrossAxisAlignment.start,
78
+ children: <Widget>[
79
Text(
82
- amountValue,
80
+ amount,
81
style: TextStyle(
84
- fontSize: 18,
85
- fontWeight: FontWeight.w600,
82
+ fontSize: 16,
83
+ fontWeight: FontWeight.normal,
84
fontFamily: 'Lato',
85
color: Theme.of(context).primaryTextTheme.title.color,
86
decoration: TextDecoration.none,
87
),
88
),
91
- Text(
92
- fiatAmountValue,
93
- style: TextStyle(
94
- fontSize: 12,
95
- fontWeight: FontWeight.w600,
96
- fontFamily: 'Lato',
97
- color: PaletteDark.pigeonBlue,
98
- decoration: TextDecoration.none,
99
- ),
89
+ Column(
90
+ crossAxisAlignment: CrossAxisAlignment.end,
91
+ children: [
92
+ Text(
93
+ amountValue,
94
+ style: TextStyle(
95
+ fontSize: 18,
96
+ fontWeight: FontWeight.w600,
97
+ fontFamily: 'Lato',
98
+ color: Theme.of(context).primaryTextTheme.title.color,
99
+ decoration: TextDecoration.none,
100
+ ),
101
+ ),
102
+ Text(
103
+ fiatAmountValue,
104
+ style: TextStyle(
105
+ fontSize: 12,
106
+ fontWeight: FontWeight.w600,
107
+ fontFamily: 'Lato',
108
+ color: PaletteDark.pigeonBlue,
109
+ decoration: TextDecoration.none,
110
+ ),
111
+ )
112
+ ],
113
)
114
],
102
- )
103
- ],
104
- ),
105
- Padding(
106
- padding: EdgeInsets.only(top: 16),
107
- child: Row(
108
- mainAxisSize: MainAxisSize.max,
109
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
110
- crossAxisAlignment: CrossAxisAlignment.start,
111
- children: <Widget>[
112
- Text(
113
- fee,
114
- style: TextStyle(
115
- fontSize: 16,
116
- fontWeight: FontWeight.normal,
117
- fontFamily: 'Lato',
118
- color: Theme.of(context).primaryTextTheme.title.color,
119
- decoration: TextDecoration.none,
120
- ),
121
- ),
122
- Column(
123
- crossAxisAlignment: CrossAxisAlignment.end,
115
+ ),
116
+ Padding(
117
+ padding: EdgeInsets.only(top: 16),
118
+ child: Row(
119
+ mainAxisSize: MainAxisSize.max,
120
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
121
+ crossAxisAlignment: CrossAxisAlignment.start,
122
+ children: <Widget>[
123
+ Text(
124
+ fee,
125
+ style: TextStyle(
126
+ fontSize: 16,
127
+ fontWeight: FontWeight.normal,
128
+ fontFamily: 'Lato',
129
+ color: Theme.of(context).primaryTextTheme.title.color,
130
+ decoration: TextDecoration.none,
131
+ ),
132
+ ),
133
+ Column(
134
+ crossAxisAlignment: CrossAxisAlignment.end,
135
+ children: [
136
+ Text(
137
+ feeValue,
138
+ style: TextStyle(
139
+ fontSize: 18,
140
+ fontWeight: FontWeight.w600,
141
+ fontFamily: 'Lato',
142
+ color: Theme.of(context).primaryTextTheme.title.color,
143
+ decoration: TextDecoration.none,
144
+ ),
145
+ ),
146
+ Text(
147
+ feeFiatAmount,
148
+ style: TextStyle(
149
+ fontSize: 12,
150
+ fontWeight: FontWeight.w600,
151
+ fontFamily: 'Lato',
152
+ color: PaletteDark.pigeonBlue,
153
+ decoration: TextDecoration.none,
154
+ ),
155
+ )
156
+ ],
157
+ )
158
+ ],
159
+ )
160
+ ),
161
+ Padding(
162
+ padding: EdgeInsets.only(top: 16),
163
+ child: Column(
164
children: [
165
Text(
126
- feeValue,
166
+ '$recipientTitle:',
167
style: TextStyle(
128
- fontSize: 18,
129
- fontWeight: FontWeight.w600,
168
+ fontSize: 16,
169
+ fontWeight: FontWeight.normal,
170
fontFamily: 'Lato',
171
color: Theme.of(context).primaryTextTheme.title.color,
172
decoration: TextDecoration.none,
173
),
174
),
135
- Text(
136
- feeFiatAmount,
137
- style: TextStyle(
138
- fontSize: 12,
139
- fontWeight: FontWeight.w600,
140
- fontFamily: 'Lato',
141
- color: PaletteDark.pigeonBlue,
142
- decoration: TextDecoration.none,
175
+ itemCount > 1
176
+ ? ListView.builder(
177
+ padding: EdgeInsets.only(top: 0),
178
+ shrinkWrap: true,
179
+ physics: NeverScrollableScrollPhysics(),
180
+ itemCount: itemCount,
181
+ itemBuilder: (context, index) {
182
+ final item = sendItemList[index];
183
+ final _address = item.address;
184
+ final _amount =
185
+ item.cryptoAmount.replaceAll(',', '.');
186
+
187
+ return Column(
188
+ children: [
189
+ Padding(
190
+ padding: EdgeInsets.only(top: 8),
191
+ child: Text(
192
+ _address,
193
+ style: TextStyle(
194
+ fontSize: 12,
195
+ fontWeight: FontWeight.w600,
196
+ fontFamily: 'Lato',
197
+ color: PaletteDark.pigeonBlue,
198
+ decoration: TextDecoration.none,
199
+ ),
200
+ )
201
+ ),
202
+ Padding(
203
+ padding: EdgeInsets.only(top: 8),
204
+ child: Row(
205
+ mainAxisSize: MainAxisSize.max,
206
+ mainAxisAlignment: MainAxisAlignment.end,
207
+ children: [
208
+ Text(
209
+ _amount,
210
+ style: TextStyle(
211
+ fontSize: 12,
212
+ fontWeight: FontWeight.w600,
213
+ fontFamily: 'Lato',
214
+ color: PaletteDark.pigeonBlue,
215
+ decoration: TextDecoration.none,
216
+ ),
217
+ )
218
+ ],
219
+ )
220
+ )
221
+ ],
222
+ );
223
+ }
224
+ )
225
+ : Padding(
226
+ padding: EdgeInsets.only(top: 8),
227
+ child: Text(
228
+ sendItemList.first.address,
229
+ style: TextStyle(
230
+ fontSize: 12,
231
+ fontWeight: FontWeight.w600,
232
+ fontFamily: 'Lato',
233
+ color: PaletteDark.pigeonBlue,
234
+ decoration: TextDecoration.none,
235
+ ),
236
),
237
)
238
],
146
- )
147
- ],
148
- )
149
- ),
150
- Padding(
151
- padding: EdgeInsets.fromLTRB(0, 16, 0, 0),
152
- child: Column(
153
- crossAxisAlignment: CrossAxisAlignment.center,
154
- children: [
155
- Text(
156
- '$recipientTitle:',
157
- style: TextStyle(
158
- fontSize: 16,
159
- fontWeight: FontWeight.normal,
160
- fontFamily: 'Lato',
161
- color: Theme.of(context).primaryTextTheme.title.color,
162
- decoration: TextDecoration.none,
163
- ),
239
),
165
- Padding(
166
- padding: EdgeInsets.only(top: 8),
167
- child: Text(
168
- recipientAddress,
169
- style: TextStyle(
170
- fontSize: 12,
171
- fontWeight: FontWeight.w600,
172
- fontFamily: 'Lato',
173
- color: PaletteDark.pigeonBlue,
174
- decoration: TextDecoration.none,
175
- ),
176
- )
177
- )
178
- ],
179
- ),
240
+ )
241
+ ],
242
)
181
- ],
243
+ )
244
);
245
}
246
}
\ No newline at end of file
lib/view_model/send/send_view_model.dart
+23
-23
@@ -1,30 +1,20 @@
1
-import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
1
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2
import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
4
-import 'package:cake_wallet/entities/balance_display_mode.dart';
5
-import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
3
import 'package:cake_wallet/entities/transaction_description.dart';
4
import 'package:cake_wallet/entities/transaction_priority.dart';
8
-import 'package:cake_wallet/monero/monero_amount_format.dart';
5
import 'package:cake_wallet/view_model/send/send_item.dart';
6
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
7
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
8
import 'package:hive/hive.dart';
13
-import 'package:intl/intl.dart';
9
import 'package:mobx/mobx.dart';
15
-import 'package:cake_wallet/entities/openalias_record.dart';
10
import 'package:cake_wallet/entities/template.dart';
17
-import 'package:cake_wallet/store/templates/send_template_store.dart';
18
-import 'package:cake_wallet/core/template_validator.dart';
11
import 'package:cake_wallet/core/address_validator.dart';
12
import 'package:cake_wallet/core/amount_validator.dart';
13
import 'package:cake_wallet/core/pending_transaction.dart';
14
import 'package:cake_wallet/core/validator.dart';
15
import 'package:cake_wallet/core/wallet_base.dart';
16
import 'package:cake_wallet/core/execution_state.dart';
25
-import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
17
import 'package:cake_wallet/bitcoin/bitcoin_transaction_credentials.dart';
27
-import 'package:cake_wallet/monero/monero_wallet.dart';
18
import 'package:cake_wallet/monero/monero_transaction_creation_credentials.dart';
19
import 'package:cake_wallet/entities/sync_status.dart';
20
import 'package:cake_wallet/entities/crypto_currency.dart';
@@ -35,7 +25,6 @@ import 'package:cake_wallet/entities/wallet_type.dart';
25
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
26
import 'package:cake_wallet/store/settings_store.dart';
27
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
38
-import 'package:cake_wallet/generated/i18n.dart';
28
29
part 'send_view_model.g.dart';
30
@@ -138,6 +127,9 @@ abstract class SendViewModelBase with Store {
127
@computed
128
ObservableList<Template> get templates => sendTemplateViewModel.templates;
129
130
+ @computed
131
+ bool get isAddReceiverButtonEnabled => _wallet is ElectrumWallet;
132
+
133
WalletType get walletType => _wallet.type;
134
final WalletBase _wallet;
135
final SettingsStore _settingsStore;
@@ -158,8 +150,18 @@ abstract class SendViewModelBase with Store {
150
151
@action
152
Future<void> commitTransaction() async {
161
- final address = ''; // FIXME: get it from item
162
- final note = ''; // FIXME: get it from item
153
+ String address = sendItemList.fold('', (previousValue, item) {
154
+ return previousValue + item.address + '\n';
155
+ });
156
+
157
+ address = address.trim();
158
+
159
+ String note = sendItemList.fold('', (previousValue, item) {
160
+ return previousValue + item.note + '\n';
161
+ });
162
+
163
+ note = note.trim();
164
+
165
try {
166
state = TransactionCommitting();
167
await pendingTransaction.commit();
@@ -185,25 +187,23 @@ abstract class SendViewModelBase with Store {
187
_settingsStore.priority[_wallet.type] = priority;
188
189
Object _credentials() {
188
- // FIXME: get it from item
189
- return null;
190
- /*final _amount = cryptoAmount.replaceAll(',', '.');
191
-
190
switch (_wallet.type) {
191
case WalletType.bitcoin:
194
- final amount = !sendAll ? _amount : null;
192
final priority = _settingsStore.priority[_wallet.type];
193
194
return BitcoinTransactionCredentials(
198
- address, amount, priority as BitcoinTransactionPriority);
195
+ sendItemList, priority as BitcoinTransactionPriority);
196
case WalletType.litecoin:
200
- final amount = !sendAll ? _amount : null;
197
final priority = _settingsStore.priority[_wallet.type];
198
199
return BitcoinTransactionCredentials(
204
- address, amount, priority as BitcoinTransactionPriority);
200
+ sendItemList, priority as BitcoinTransactionPriority);
201
case WalletType.monero:
206
- final amount = !sendAll ? _amount : null;
202
+ final _item = sendItemList.first;
203
+ final address = _item.address;
204
+ final amount = _item.sendAll
205
+ ? null
206
+ : _item.cryptoAmount.replaceAll(',', '.');
207
final priority = _settingsStore.priority[_wallet.type];
208
209
return MoneroTransactionCreationCredentials(
@@ -213,7 +213,7 @@ abstract class SendViewModelBase with Store {
213
amount: amount);
214
default:
215
return null;
216
- }*/
216
+ }
217
}
218
219
String displayFeeRate(dynamic priority) {
res/values/strings_de.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Betrag",
285
"transaction_details_fee" : "Gebühr",
286
"transaction_details_copied" : "${title} in die Zwischenablage kopiert",
287
- "transaction_details_recipient_address" : "Empfängeradresse",
287
+ "transaction_details_recipient_address" : "Empfängeradressen",
288
289
290
"wallet_list_title" : "Monero-Wallet",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
484
485
"outdated_electrum_wallet_receive_warning": "Wenn diese Brieftasche einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Brieftasche ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
486
- "do_not_show_me": "Zeig mir das nicht noch einmal"
486
+ "do_not_show_me": "Zeig mir das nicht noch einmal",
487
+
488
+ "add_receiver" : "Empfänger hinzufügen"
489
}
res/values/strings_en.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Amount",
285
"transaction_details_fee" : "Fee",
286
"transaction_details_copied" : "${title} copied to Clipboard",
287
- "transaction_details_recipient_address" : "Recipient address",
287
+ "transaction_details_recipient_address" : "Recipient addresses",
288
289
290
"wallet_list_title" : "Monero Wallet",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "If this wallet has a 12-word seed and was created in Cake, DO NOT deposit Bitcoin into this wallet. Any BTC transferred to this wallet may be lost. Create a new 24-word wallet (tap the menu at the top right, select Wallets, choose Create New Wallet, then select Bitcoin) and IMMEDIATELY move your BTC there. New (24-word) BTC wallets from Cake are secure",
486
- "do_not_show_me": "Do not show me this again"
486
+ "do_not_show_me": "Do not show me this again",
487
+
488
+ "add_receiver" : "Add receiver"
489
}
\ No newline at end of file
res/values/strings_es.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Cantidad",
285
"transaction_details_fee" : "Cuota",
286
"transaction_details_copied" : "${title} Copiado al portapapeles",
287
- "transaction_details_recipient_address" : "Dirección del receptor",
287
+ "transaction_details_recipient_address" : "Direcciones de destinatarios",
288
289
290
"wallet_list_title" : "Monedero Monero",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Si esta billetera tiene una semilla de 12 palabras y se creó en Cake, NO deposite Bitcoin en esta billetera. Cualquier BTC transferido a esta billetera se puede perder. Cree una nueva billetera de 24 palabras (toque el menú en la parte superior derecha, seleccione Monederos, elija Crear nueva billetera, luego seleccione Bitcoin) e INMEDIATAMENTE mueva su BTC allí. Las nuevas carteras BTC (24 palabras) de Cake son seguras",
486
- "do_not_show_me": "no me muestres esto otra vez"
486
+ "do_not_show_me": "no me muestres esto otra vez",
487
+
488
+ "add_receiver" : "Agregar receptor"
489
}
\ No newline at end of file
res/values/strings_hi.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "रकम",
285
"transaction_details_fee" : "शुल्क",
286
"transaction_details_copied" : "${title} क्लिपबोर्ड पर नकल",
287
- "transaction_details_recipient_address" : "प्राप्तकर्ता का पता",
287
+ "transaction_details_recipient_address" : "प्राप्तकर्ता के पते",
288
289
290
"wallet_list_title" : "Monero बटुआ",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "अगर इस वॉलेट में 12 शब्दों का बीज है और इसे केक में बनाया गया है, तो इस वॉलेट में बिटकॉइन जमा न करें। इस वॉलेट में स्थानांतरित किया गया कोई भी बीटीसी खो सकता है। एक नया 24-शब्द वॉलेट बनाएं (ऊपर दाईं ओर स्थित मेनू पर टैप करें, वॉलेट चुनें, नया वॉलेट बनाएं चुनें, फिर बिटकॉइन चुनें) और तुरंत अपना बीटीसी वहां ले जाएं। केक से नए (24-शब्द) बीटीसी वॉलेट सुरक्षित हैं",
486
- "do_not_show_me": "मुझे यह फिर न दिखाएं"
486
+ "do_not_show_me": "मुझे यह फिर न दिखाएं",
487
+
488
+ "add_receiver" : "रिसीवर जोड़ें"
489
}
\ No newline at end of file
res/values/strings_hr.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Iznos",
285
"transaction_details_fee" : "Naknada",
286
"transaction_details_copied" : "${title} kopiran u međuspremnik",
287
- "transaction_details_recipient_address" : "Primateljeva adresa",
287
+ "transaction_details_recipient_address" : "Adrese primatelja",
288
289
290
"wallet_list_title" : "Monero novčanik",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Ako ovaj novčanik sadrži sjeme od 12 riječi i stvoren je u Torti, NEMOJTE polagati Bitcoin u ovaj novčanik. Bilo koji BTC prebačen u ovaj novčanik može se izgubiti. Stvorite novi novčanik od 24 riječi (taknite izbornik u gornjem desnom dijelu, odaberite Novčanici, odaberite Stvori novi novčanik, a zatim odaberite Bitcoin) i ODMAH premjestite svoj BTC tamo. Novi BTC novčanici (s 24 riječi) tvrtke Cake sigurni su",
486
- "do_not_show_me": "Ne pokazuj mi ovo više"
486
+ "do_not_show_me": "Ne pokazuj mi ovo više",
487
+
488
+ "add_receiver" : "Dodajte prijamnik"
489
}
\ No newline at end of file
res/values/strings_it.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Ammontare",
285
"transaction_details_fee" : "Commissione",
286
"transaction_details_copied" : "${title} copiati negli Appunti",
287
- "transaction_details_recipient_address" : "Indirizzo destinatario",
287
+ "transaction_details_recipient_address" : "Indirizzi dei destinatari",
288
289
290
"wallet_list_title" : "Portafoglio Monero",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Il valore dell'importo deve essere maggiore o uguale a ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Se questo portafoglio ha un seme di 12 parole ed è stato creato in Cake, NON depositare Bitcoin in questo portafoglio. Qualsiasi BTC trasferito su questo portafoglio potrebbe andare perso. Crea un nuovo portafoglio di 24 parole (tocca il menu in alto a destra, seleziona Portafogli, scegli Crea nuovo portafoglio, quindi seleziona Bitcoin) e sposta IMMEDIATAMENTE lì il tuo BTC. I nuovi portafogli BTC (24 parole) di Cake sono sicuri",
486
- "do_not_show_me": "Non mostrarmelo di nuovo"
486
+ "do_not_show_me": "Non mostrarmelo di nuovo",
487
+
488
+ "add_receiver" : "Aggiungi ricevitore"
489
}
\ No newline at end of file
res/values/strings_ja.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "量",
285
"transaction_details_fee" : "費用",
286
"transaction_details_copied" : "${title} クリップボードにコピーしました",
287
- "transaction_details_recipient_address" : "受取人の住所",
287
+ "transaction_details_recipient_address" : "受信者のアドレス",
288
289
290
"wallet_list_title" : "Monero 財布",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "金額の値は以上でなければなりません ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "このウォレットに 12 ワードのシードがあり、Cake で作成された場合、このウォレットにビットコインを入金しないでください。 このウォレットに転送された BTC は失われる可能性があります。 新しい 24 ワードのウォレットを作成し (右上のメニューをタップし、[ウォレット]、[新しいウォレットの作成]、[ビットコイン] の順に選択)、すぐに BTC をそこに移動します。 Cake の新しい (24 ワード) BTC ウォレットは安全です",
486
- "do_not_show_me": "また僕にこれを見せないでください"
486
+ "do_not_show_me": "また僕にこれを見せないでください",
487
+
488
+ "add_receiver" : "レシーバーを追加"
489
}
\ No newline at end of file
res/values/strings_ko.arb
+3
-1
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "금액은 다음보다 크거나 같아야합니다 ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "이 지갑에 12 단어 시드가 있고 Cake에서 생성 된 경우이 지갑에 비트 코인을 입금하지 마십시오. 이 지갑으로 전송 된 모든 BTC는 손실 될 수 있습니다. 새로운 24 단어 지갑을 생성하고 (오른쪽 상단의 메뉴를 탭하고 지갑을 선택한 다음 새 지갑 생성을 선택한 다음 비트 코인을 선택하십시오) 즉시 BTC를 그곳으로 이동하십시오. Cake의 새로운 (24 단어) BTC 지갑은 안전합니다",
486
- "do_not_show_me": "나를 다시 표시하지 않음"
486
+ "do_not_show_me": "나를 다시 표시하지 않음",
487
+
488
+ "add_receiver" : "수신기 추가"
489
}
\ No newline at end of file
res/values/strings_nl.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Bedrag",
285
"transaction_details_fee" : "Vergoeding",
286
"transaction_details_copied" : "${title} gekopieerd naar het klembord",
287
- "transaction_details_recipient_address" : "Adres van de ontvanger",
287
+ "transaction_details_recipient_address" : "Adressen van ontvangers",
288
289
290
"wallet_list_title" : "Monero portemonnee",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Waarde van het bedrag moet meer of gelijk zijn aan ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Als deze portemonnee een seed van 12 woorden heeft en is gemaakt in Cake, stort dan GEEN Bitcoin in deze portemonnee. Elke BTC die naar deze portemonnee is overgebracht, kan verloren gaan. Maak een nieuwe portemonnee van 24 woorden (tik op het menu rechtsboven, selecteer Portefeuilles, kies Nieuwe portemonnee maken en selecteer vervolgens Bitcoin) en verplaats je BTC ONMIDDELLIJK daar. Nieuwe (24-woorden) BTC-portefeuilles van Cake zijn veilig",
486
- "do_not_show_me": "laat me dit niet opnieuw zien"
486
+ "do_not_show_me": "laat me dit niet opnieuw zien",
487
+
488
+ "add_receiver" : "Ontvanger toevoegen"
489
}
\ No newline at end of file
res/values/strings_pl.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Ilość",
285
"transaction_details_fee" : "Opłata",
286
"transaction_details_copied" : "${title} skopiowane do schowka",
287
- "transaction_details_recipient_address" : "Adres odbiorcy",
287
+ "transaction_details_recipient_address" : "Adresy odbiorców",
288
289
290
"wallet_list_title" : "Portfel Monero",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Wartość kwoty musi być większa lub równa ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Jeśli ten portfel ma 12-wyrazowy seed i został utworzony w Cake, NIE Wpłacaj Bitcoina do tego portfela. Wszelkie BTC przeniesione do tego portfela mogą zostać utracone. Utwórz nowy portfel z 24 słowami (dotknij menu w prawym górnym rogu, wybierz Portfele, wybierz Utwórz nowy portfel, a następnie Bitcoin) i NATYCHMIAST przenieś tam swoje BTC. Nowe (24 słowa) portfele BTC firmy Cake są bezpieczne",
486
- "do_not_show_me": "Nie pokazuj mi tego ponownie"
486
+ "do_not_show_me": "Nie pokazuj mi tego ponownie",
487
+
488
+ "add_receiver" : "Dodaj odbiorcę"
489
}
\ No newline at end of file
res/values/strings_pt.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Quantia",
285
"transaction_details_fee" : "Taxa",
286
"transaction_details_copied" : "${title} copiados para a área de transferência",
287
- "transaction_details_recipient_address" : "Endereço do destinatário",
287
+ "transaction_details_recipient_address" : "Endereços de destinatários",
288
289
290
"wallet_list_title" : "Carteira Monero",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "O valor do montante deve ser maior ou igual a ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Se esta carteira tiver uma semente de 12 palavras e foi criada no Cake, NÃO deposite Bitcoin nesta carteira. Qualquer BTC transferido para esta carteira pode ser perdido. Crie uma nova carteira de 24 palavras (toque no menu no canto superior direito, selecione Carteiras, escolha Criar Nova Carteira e selecione Bitcoin) e mova IMEDIATAMENTE seu BTC para lá. As novas carteiras BTC (24 palavras) da Cake são seguras",
486
- "do_not_show_me": "não me mostre isso novamente"
486
+ "do_not_show_me": "não me mostre isso novamente",
487
+
488
+ "add_receiver" : "Adicionar receptor"
489
}
\ No newline at end of file
res/values/strings_ru.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Сумма",
285
"transaction_details_fee" : "Комиссия",
286
"transaction_details_copied" : "${title} скопировано в буфер обмена",
287
- "transaction_details_recipient_address" : "Адрес получателя",
287
+ "transaction_details_recipient_address" : "Адреса получателей",
288
289
290
"wallet_list_title" : "Monero Кошелёк",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Сумма должна быть больше или равна ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Если этот кошелек имеет мнемоническую фразу из 12 слов и был создан в Cake, НЕ переводите биткойны на этот кошелек. Любые BTC, переведенные на этот кошелек, могут быть потеряны. Создайте новый кошелек с мнемоническои фразы из 24 слов (коснитесь меню в правом верхнем углу, выберите «Кошельки», выберите «Создать новый кошелек», затем выберите «Bitcoin») и НЕМЕДЛЕННО переведите туда свои BTC. Новые (24 слова) кошельки BTC от Cake безопасны",
486
- "do_not_show_me": "Не показывай мне это больше"
486
+ "do_not_show_me": "Не показывай мне это больше",
487
+
488
+ "add_receiver" : "Добавить получателя"
489
}
\ No newline at end of file
res/values/strings_uk.arb
+4
-2
@@ -284,7 +284,7 @@
284
"transaction_details_amount" : "Сума",
285
"transaction_details_fee" : "Комісія",
286
"transaction_details_copied" : "${title} скопійовано в буфер обміну",
287
- "transaction_details_recipient_address" : "Адреса отримувача",
287
+ "transaction_details_recipient_address" : "Адреси одержувачів",
288
289
290
"wallet_list_title" : "Monero Гаманець",
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "Значення суми має бути більшим або дорівнювати ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "Якщо цей гаманець має мнемонічну фразу з 12 слів і був створений у Cake, НЕ переводьте біткойни на цей гаманець. Будь-які BTC, переведений на цей гаманець, можуть бути втраченими. Створіть новий гаманець з мнемонічною фразою з 24 слів (торкніться меню у верхньому правому куті, виберіть Гаманці, виберіть Створити новий гаманець, потім виберіть Bitcoin) і НЕГАЙНО переведіть туди свії BTC. Нові (з мнемонічною фразою з 24 слів) гаманці BTC від Cake надійно захищені",
486
- "do_not_show_me": "Не показуй мені це знову"
486
+ "do_not_show_me": "Не показуй мені це знову",
487
+
488
+ "add_receiver" : "Додати одержувача"
489
}
\ No newline at end of file
res/values/strings_zh.arb
+3
-1
@@ -483,5 +483,7 @@
483
"moonpay_alert_text" : "金额的价值必须大于或等于 ${minAmount} ${fiatCurrency}",
484
485
"outdated_electrum_wallet_receive_warning": "如果这个钱包有一个 12 字的种子并且是在 Cake 中创建的,不要将比特币存入这个钱包。 任何转移到此钱包的 BTC 都可能丢失。 创建一个新的 24 字钱包(点击右上角的菜单,选择钱包,选择创建新钱包,然后选择比特币)并立即将您的 BTC 移到那里。 Cake 的新(24 字)BTC 钱包是安全的",
486
- "do_not_show_me": "不再提示"
486
+ "do_not_show_me": "不再提示",
487
+
488
+ "add_receiver" : "添加接收器"
489
}
\ No newline at end of file