mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 17:57:40 +00:00
Merge branch 'staging' into httpsend-error-fix
This commit is contained in:
commit
d38d482b87
10 changed files with 573 additions and 145 deletions
|
@ -289,7 +289,7 @@ class _NewWalletOptionsViewState extends ConsumerState<NewWalletOptionsView> {
|
|||
child: Center(
|
||||
child: Text(
|
||||
"You may add a BIP39 passphrase. This is optional. "
|
||||
"You will need BOTH you seed and your passphrase to recover the wallet.",
|
||||
"You will need BOTH your seed and your passphrase to recover the wallet.",
|
||||
style: Util.isDesktop
|
||||
? STextStyles.desktopTextExtraSmall(context)
|
||||
.copyWith(
|
||||
|
|
|
@ -252,10 +252,17 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
},
|
||||
);
|
||||
} else {
|
||||
final memo =
|
||||
manager.coin == Coin.stellar || manager.coin == Coin.stellarTestnet
|
||||
? model.trade!.payInExtraId.isNotEmpty
|
||||
? model.trade!.payInExtraId
|
||||
: null
|
||||
: null;
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: address,
|
||||
amount: amount,
|
||||
args: {
|
||||
"memo": memo,
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
},
|
||||
|
@ -568,6 +575,74 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
if (model.trade!.payInExtraId.isNotEmpty)
|
||||
RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Memo",
|
||||
style:
|
||||
STextStyles.itemSubtitle(context),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final data = ClipboardData(
|
||||
text:
|
||||
model.trade!.payInExtraId);
|
||||
await clipboard.setData(data);
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message:
|
||||
"Copied to clipboard",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemIcons,
|
||||
width: 10,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
Text(
|
||||
"Copy",
|
||||
style:
|
||||
STextStyles.link2(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
model.trade!.payInExtraId,
|
||||
style:
|
||||
STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (model.trade!.payInExtraId.isNotEmpty)
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
child: Row(
|
||||
children: [
|
||||
|
|
|
@ -268,10 +268,17 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
|
||||
// if not firo then do normal send
|
||||
if (shouldSendPublicFiroFunds == null) {
|
||||
final memo =
|
||||
manager.coin == Coin.stellar || manager.coin == Coin.stellarTestnet
|
||||
? trade.payInExtraId.isNotEmpty
|
||||
? trade.payInExtraId
|
||||
: null
|
||||
: null;
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: address,
|
||||
amount: amount,
|
||||
args: {
|
||||
"memo": memo,
|
||||
"feeRate": FeeRateType.average,
|
||||
// ref.read(feeRateTypeStateProvider)
|
||||
},
|
||||
|
|
|
@ -850,6 +850,81 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
: const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (trade.payInExtraId.isNotEmpty && !sentFromStack && !hasTx)
|
||||
RoundedWhiteContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Memo",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
isDesktop
|
||||
? IconCopyButton(
|
||||
data: trade.payInExtraId,
|
||||
)
|
||||
: GestureDetector(
|
||||
onTap: () async {
|
||||
final address = trade.payInExtraId;
|
||||
await Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: address,
|
||||
),
|
||||
);
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
message: "Copied to clipboard",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.copy,
|
||||
width: 12,
|
||||
height: 12,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.infoItemIcons,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 4,
|
||||
),
|
||||
Text(
|
||||
"Copy",
|
||||
style: STextStyles.link2(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
trade.payInExtraId,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (trade.payInExtraId.isNotEmpty && !sentFromStack && !hasTx)
|
||||
isDesktop
|
||||
? const _Divider()
|
||||
: const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
|
|
|
@ -103,6 +103,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
late TextEditingController noteController;
|
||||
late TextEditingController onChainNoteController;
|
||||
late TextEditingController feeController;
|
||||
late TextEditingController memoController;
|
||||
|
||||
late final SendViewAutoFillData? _data;
|
||||
|
||||
|
@ -111,6 +112,9 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
final _onChainNoteFocusNode = FocusNode();
|
||||
final _cryptoFocus = FocusNode();
|
||||
final _baseFocus = FocusNode();
|
||||
final _memoFocus = FocusNode();
|
||||
|
||||
late final bool isStellar;
|
||||
|
||||
Amount? _amountToSend;
|
||||
Amount? _cachedAmountToSend;
|
||||
|
@ -522,10 +526,15 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
},
|
||||
);
|
||||
} else {
|
||||
final memo =
|
||||
manager.coin == Coin.stellar || manager.coin == Coin.stellarTestnet
|
||||
? memoController.text
|
||||
: null;
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: _address!,
|
||||
amount: amount,
|
||||
args: {
|
||||
"memo": memo,
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
"satsPerVByte": isCustomFee ? customFeeRate : null,
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -622,6 +631,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
walletId = widget.walletId;
|
||||
clipboard = widget.clipboard;
|
||||
scanner = widget.barcodeScanner;
|
||||
isStellar = coin == Coin.stellar || coin == Coin.stellarTestnet;
|
||||
|
||||
sendToController = TextEditingController();
|
||||
cryptoAmountController = TextEditingController();
|
||||
|
@ -629,6 +639,7 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
noteController = TextEditingController();
|
||||
onChainNoteController = TextEditingController();
|
||||
feeController = TextEditingController();
|
||||
memoController = TextEditingController();
|
||||
|
||||
onCryptoAmountChanged = _cryptoAmountChanged;
|
||||
cryptoAmountController.addListener(onCryptoAmountChanged);
|
||||
|
@ -704,12 +715,14 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
noteController.dispose();
|
||||
onChainNoteController.dispose();
|
||||
feeController.dispose();
|
||||
memoController.dispose();
|
||||
|
||||
_noteFocusNode.dispose();
|
||||
_onChainNoteFocusNode.dispose();
|
||||
_addressFocusNode.dispose();
|
||||
_cryptoFocus.dispose();
|
||||
_baseFocus.dispose();
|
||||
_memoFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -1298,6 +1311,88 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
if (isStellar)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key("sendViewMemoFieldKey"),
|
||||
controller: memoController,
|
||||
readOnly: false,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
focusNode: _memoFocus,
|
||||
style: STextStyles.field(context),
|
||||
onChanged: (_) {
|
||||
setState(() {});
|
||||
},
|
||||
decoration: standardInputDecoration(
|
||||
"Enter memo (optional)",
|
||||
_memoFocus,
|
||||
context,
|
||||
).copyWith(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 16,
|
||||
top: 6,
|
||||
bottom: 8,
|
||||
right: 5,
|
||||
),
|
||||
suffixIcon: Padding(
|
||||
padding: memoController.text.isEmpty
|
||||
? const EdgeInsets.only(right: 8)
|
||||
: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
memoController.text.isNotEmpty
|
||||
? TextFieldIconButton(
|
||||
semanticsLabel:
|
||||
"Clear Button. Clears The Memo Field Input.",
|
||||
key: const Key(
|
||||
"sendViewClearMemoFieldButtonKey"),
|
||||
onTap: () {
|
||||
memoController.text = "";
|
||||
setState(() {});
|
||||
},
|
||||
child: const XIcon(),
|
||||
)
|
||||
: TextFieldIconButton(
|
||||
semanticsLabel:
|
||||
"Paste Button. Pastes From Clipboard To Memo Field Input.",
|
||||
key: const Key(
|
||||
"sendViewPasteMemoFieldButtonKey"),
|
||||
onTap: () async {
|
||||
final ClipboardData? data =
|
||||
await clipboard.getData(
|
||||
Clipboard
|
||||
.kTextPlain);
|
||||
if (data?.text != null &&
|
||||
data!
|
||||
.text!.isNotEmpty) {
|
||||
String content =
|
||||
data.text!.trim();
|
||||
|
||||
memoController.text =
|
||||
content.trim();
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
child: const ClipboardIcon(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Builder(
|
||||
builder: (_) {
|
||||
final error = _updateInvalidAddressText(
|
||||
|
@ -1817,7 +1912,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
),
|
||||
child: TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions: Util.isDesktop ? false : true,
|
||||
enableSuggestions:
|
||||
Util.isDesktop ? false : true,
|
||||
maxLength: 256,
|
||||
controller: onChainNoteController,
|
||||
focusNode: _onChainNoteFocusNode,
|
||||
|
@ -1828,7 +1924,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
_onChainNoteFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: onChainNoteController.text.isNotEmpty
|
||||
suffixIcon: onChainNoteController
|
||||
.text.isNotEmpty
|
||||
? Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 0),
|
||||
|
@ -1839,7 +1936,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
onChainNoteController.text = "";
|
||||
onChainNoteController
|
||||
.text = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
|
@ -1856,7 +1954,8 @@ class _SendViewState extends ConsumerState<SendView> {
|
|||
height: 12,
|
||||
),
|
||||
Text(
|
||||
(coin == Coin.epicCash) ? "Local Note (optional)"
|
||||
(coin == Coin.epicCash)
|
||||
? "Local Note (optional)"
|
||||
: "Note (optional)",
|
||||
style: STextStyles.smallMed12(context),
|
||||
textAlign: TextAlign.left,
|
||||
|
|
|
@ -167,77 +167,77 @@ class HiddenSettings extends StatelessWidget {
|
|||
// ),
|
||||
// );
|
||||
// }),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Consumer(builder: (_, ref, __) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
ref
|
||||
.read(priceAnd24hChangeNotifierProvider)
|
||||
.tokenContractAddressesToCheck
|
||||
.add(
|
||||
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
|
||||
ref
|
||||
.read(priceAnd24hChangeNotifierProvider)
|
||||
.tokenContractAddressesToCheck
|
||||
.add(
|
||||
"0xdAC17F958D2ee523a2206206994597C13D831ec7");
|
||||
await ref
|
||||
.read(priceAnd24hChangeNotifierProvider)
|
||||
.updatePrice();
|
||||
|
||||
final x = ref
|
||||
.read(priceAnd24hChangeNotifierProvider)
|
||||
.getTokenPrice(
|
||||
"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
|
||||
|
||||
print(
|
||||
"PRICE 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48: $x");
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
child: Text(
|
||||
"Click me",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Consumer(builder: (_, ref, __) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
// final erc20 = Erc20ContractInfo(
|
||||
// contractAddress: 'some con',
|
||||
// name: "loonamsn",
|
||||
// symbol: "DD",
|
||||
// decimals: 19,
|
||||
// const SizedBox(
|
||||
// height: 12,
|
||||
// ),
|
||||
// Consumer(builder: (_, ref, __) {
|
||||
// return GestureDetector(
|
||||
// onTap: () async {
|
||||
// ref
|
||||
// .read(priceAnd24hChangeNotifierProvider)
|
||||
// .tokenContractAddressesToCheck
|
||||
// .add(
|
||||
// "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
|
||||
// ref
|
||||
// .read(priceAnd24hChangeNotifierProvider)
|
||||
// .tokenContractAddressesToCheck
|
||||
// .add(
|
||||
// "0xdAC17F958D2ee523a2206206994597C13D831ec7");
|
||||
// await ref
|
||||
// .read(priceAnd24hChangeNotifierProvider)
|
||||
// .updatePrice();
|
||||
//
|
||||
// final x = ref
|
||||
// .read(priceAnd24hChangeNotifierProvider)
|
||||
// .getTokenPrice(
|
||||
// "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48");
|
||||
//
|
||||
// print(
|
||||
// "PRICE 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48: $x");
|
||||
// },
|
||||
// child: RoundedWhiteContainer(
|
||||
// child: Text(
|
||||
// "Click me",
|
||||
// style: STextStyles.button(context).copyWith(
|
||||
// color: Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .accentColorDark),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
//
|
||||
// final json = erc20.toJson();
|
||||
//
|
||||
// print(json);
|
||||
//
|
||||
// final ee = EthContractInfo.fromJson(json);
|
||||
//
|
||||
// print(ee);
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
child: Text(
|
||||
"Click me",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
// }),
|
||||
// const SizedBox(
|
||||
// height: 12,
|
||||
// ),
|
||||
// Consumer(builder: (_, ref, __) {
|
||||
// return GestureDetector(
|
||||
// onTap: () async {
|
||||
// // final erc20 = Erc20ContractInfo(
|
||||
// // contractAddress: 'some con',
|
||||
// // name: "loonamsn",
|
||||
// // symbol: "DD",
|
||||
// // decimals: 19,
|
||||
// // );
|
||||
// //
|
||||
// // final json = erc20.toJson();
|
||||
// //
|
||||
// // print(json);
|
||||
// //
|
||||
// // final ee = EthContractInfo.fromJson(json);
|
||||
// //
|
||||
// // print(ee);
|
||||
// },
|
||||
// child: RoundedWhiteContainer(
|
||||
// child: Text(
|
||||
// "Click me",
|
||||
// style: STextStyles.button(context).copyWith(
|
||||
// color: Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .accentColorDark),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
|
|
|
@ -155,6 +155,23 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
|
|||
height: 1,
|
||||
color: Theme.of(context).extension<StackColors>()!.background,
|
||||
),
|
||||
if (ref.watch(desktopExchangeModelProvider
|
||||
.select((value) => value!.trade?.payInExtraId)) !=
|
||||
null)
|
||||
DesktopStepItem(
|
||||
vertical: true,
|
||||
label: "Memo",
|
||||
value: ref.watch(desktopExchangeModelProvider
|
||||
.select((value) => value!.trade?.payInExtraId)) ??
|
||||
"Error",
|
||||
),
|
||||
if (ref.watch(desktopExchangeModelProvider
|
||||
.select((value) => value!.trade?.payInExtraId)) !=
|
||||
null)
|
||||
Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).extension<StackColors>()!.background,
|
||||
),
|
||||
DesktopStepItem(
|
||||
label: "Amount",
|
||||
value:
|
||||
|
|
|
@ -97,12 +97,16 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
late TextEditingController cryptoAmountController;
|
||||
late TextEditingController baseAmountController;
|
||||
// late TextEditingController feeController;
|
||||
late TextEditingController memoController;
|
||||
|
||||
late final SendViewAutoFillData? _data;
|
||||
|
||||
final _addressFocusNode = FocusNode();
|
||||
final _cryptoFocus = FocusNode();
|
||||
final _baseFocus = FocusNode();
|
||||
final _memoFocus = FocusNode();
|
||||
|
||||
late final bool isStellar;
|
||||
|
||||
String? _note;
|
||||
String? _onChainNote;
|
||||
|
@ -326,10 +330,12 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
},
|
||||
);
|
||||
} else {
|
||||
final memo = isStellar ? memoController.text : null;
|
||||
txDataFuture = manager.prepareSend(
|
||||
address: _address!,
|
||||
amount: amount,
|
||||
args: {
|
||||
"memo": memo,
|
||||
"feeRate": ref.read(feeRateTypeStateProvider),
|
||||
"satsPerVByte": isCustomFee ? customFeeRate : null,
|
||||
"UTXOs": (manager.hasCoinControlSupport &&
|
||||
|
@ -663,6 +669,23 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> pasteMemo() async {
|
||||
if (memoController.text.isNotEmpty) {
|
||||
setState(() {
|
||||
memoController.text = "";
|
||||
});
|
||||
} else {
|
||||
final ClipboardData? data = await clipboard.getData(Clipboard.kTextPlain);
|
||||
if (data?.text != null && data!.text!.isNotEmpty) {
|
||||
String content = data.text!.trim();
|
||||
|
||||
setState(() {
|
||||
memoController.text = content;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fiatTextFieldOnChanged(String baseAmountString) {
|
||||
final baseAmount = Amount.tryParseFiatString(
|
||||
baseAmountString,
|
||||
|
@ -762,10 +785,12 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
coin = ref.read(walletsChangeNotifierProvider).getManager(walletId).coin;
|
||||
clipboard = widget.clipboard;
|
||||
scanner = widget.barcodeScanner;
|
||||
isStellar = coin == Coin.stellar || coin == Coin.stellarTestnet;
|
||||
|
||||
sendToController = TextEditingController();
|
||||
cryptoAmountController = TextEditingController();
|
||||
baseAmountController = TextEditingController();
|
||||
memoController = TextEditingController();
|
||||
// feeController = TextEditingController();
|
||||
|
||||
onCryptoAmountChanged = _cryptoAmountChanged;
|
||||
|
@ -814,11 +839,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
sendToController.dispose();
|
||||
cryptoAmountController.dispose();
|
||||
baseAmountController.dispose();
|
||||
memoController.dispose();
|
||||
// feeController.dispose();
|
||||
|
||||
_addressFocusNode.dispose();
|
||||
_cryptoFocus.dispose();
|
||||
_baseFocus.dispose();
|
||||
_memoFocus.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
@ -1367,6 +1394,67 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
}
|
||||
},
|
||||
),
|
||||
if (isStellar)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
if (isStellar)
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
key: const Key("sendViewMemoFieldKey"),
|
||||
controller: memoController,
|
||||
readOnly: false,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
focusNode: _memoFocus,
|
||||
onChanged: (_) {
|
||||
setState(() {});
|
||||
},
|
||||
style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveText,
|
||||
height: 1.8,
|
||||
),
|
||||
decoration: standardInputDecoration(
|
||||
"Enter memo (optional)",
|
||||
_memoFocus,
|
||||
context,
|
||||
desktopMed: true,
|
||||
).copyWith(
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 16,
|
||||
top: 11,
|
||||
bottom: 12,
|
||||
right: 5,
|
||||
),
|
||||
suffixIcon: Padding(
|
||||
padding: memoController.text.isEmpty
|
||||
? const EdgeInsets.only(right: 8)
|
||||
: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
key: const Key("sendViewPasteMemoButtonKey"),
|
||||
onTap: pasteMemo,
|
||||
child: memoController.text.isEmpty
|
||||
? const ClipboardIcon()
|
||||
: const XIcon(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (!isPaynymSend)
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
|
|
|
@ -3352,6 +3352,30 @@ class FiroWallet extends CoinServiceAPI
|
|||
|
||||
List<Map<String, dynamic>> allTransactions = [];
|
||||
|
||||
// some lelantus transactions aren't fetched via wallet addresses so they
|
||||
// will never show as confirmed in the gui.
|
||||
final unconfirmedTransactions =
|
||||
await db.getTransactions(walletId).filter().heightIsNull().findAll();
|
||||
for (final tx in unconfirmedTransactions) {
|
||||
final txn = await cachedElectrumXClient.getTransaction(
|
||||
txHash: tx.txid,
|
||||
verbose: true,
|
||||
coin: coin,
|
||||
);
|
||||
final height = txn["height"] as int?;
|
||||
|
||||
if (height != null) {
|
||||
// tx was mined
|
||||
// add to allTxHashes
|
||||
final info = {
|
||||
"tx_hash": tx.txid,
|
||||
"height": height,
|
||||
"address": tx.address.value?.value,
|
||||
};
|
||||
allTxHashes.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
// final currentHeight = await chainHeight;
|
||||
|
||||
for (final txHash in allTxHashes) {
|
||||
|
|
|
@ -181,6 +181,41 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
return exists;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> prepareSend(
|
||||
{required String address,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args}) async {
|
||||
try {
|
||||
final feeRate = args?["feeRate"];
|
||||
var fee = 1000;
|
||||
if (feeRate is FeeRateType) {
|
||||
final theFees = await fees;
|
||||
switch (feeRate) {
|
||||
case FeeRateType.fast:
|
||||
fee = theFees.fast;
|
||||
case FeeRateType.slow:
|
||||
fee = theFees.slow;
|
||||
case FeeRateType.average:
|
||||
default:
|
||||
fee = theFees.medium;
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> txData = {
|
||||
"fee": fee,
|
||||
"address": address,
|
||||
"recipientAmt": amount,
|
||||
"memo": args?["memo"] as String?,
|
||||
};
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
return txData;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Error getting fees $e - $s", level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> confirmSend({required Map<String, dynamic> txData}) async {
|
||||
final secretSeed = await _secureStore.read(key: '${_walletId}_secretSeed');
|
||||
|
@ -188,27 +223,33 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
AccountResponse sender =
|
||||
await stellarSdk.accounts.account(senderKeyPair.accountId);
|
||||
final amountToSend = txData['recipientAmt'] as Amount;
|
||||
final memo = txData["memo"] as String?;
|
||||
|
||||
//First check if account exists, can be skipped, but if the account does not exist,
|
||||
// the transaction fee will be charged when the transaction fails.
|
||||
bool validAccount = await _accountExists(txData['address'] as String);
|
||||
Transaction transaction;
|
||||
TransactionBuilder transactionBuilder;
|
||||
|
||||
if (!validAccount) {
|
||||
//Fund the account, user must ensure account is correct
|
||||
CreateAccountOperationBuilder createAccBuilder =
|
||||
CreateAccountOperationBuilder(
|
||||
txData['address'] as String, amountToSend.decimal.toString());
|
||||
transaction = TransactionBuilder(sender)
|
||||
.addOperation(createAccBuilder.build())
|
||||
.build();
|
||||
transactionBuilder =
|
||||
TransactionBuilder(sender).addOperation(createAccBuilder.build());
|
||||
} else {
|
||||
transaction = TransactionBuilder(sender)
|
||||
.addOperation(PaymentOperationBuilder(txData['address'] as String,
|
||||
Asset.NATIVE, amountToSend.decimal.toString())
|
||||
.build())
|
||||
.build();
|
||||
transactionBuilder = TransactionBuilder(sender).addOperation(
|
||||
PaymentOperationBuilder(txData['address'] as String, Asset.NATIVE,
|
||||
amountToSend.decimal.toString())
|
||||
.build());
|
||||
}
|
||||
|
||||
if (memo != null) {
|
||||
transactionBuilder.addMemo(MemoText(memo));
|
||||
}
|
||||
|
||||
final transaction = transactionBuilder.build();
|
||||
|
||||
transaction.sign(senderKeyPair, stellarNetwork);
|
||||
try {
|
||||
SubmitTransactionResponse response = await stellarSdk
|
||||
|
@ -441,40 +482,6 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
Future<String?> get mnemonicString =>
|
||||
_secureStore.read(key: '${_walletId}_mnemonic');
|
||||
|
||||
@override
|
||||
Future<Map<String, dynamic>> prepareSend(
|
||||
{required String address,
|
||||
required Amount amount,
|
||||
Map<String, dynamic>? args}) async {
|
||||
try {
|
||||
final feeRate = args?["feeRate"];
|
||||
var fee = 1000;
|
||||
if (feeRate is FeeRateType) {
|
||||
final theFees = await fees;
|
||||
switch (feeRate) {
|
||||
case FeeRateType.fast:
|
||||
fee = theFees.fast;
|
||||
case FeeRateType.slow:
|
||||
fee = theFees.slow;
|
||||
case FeeRateType.average:
|
||||
default:
|
||||
fee = theFees.medium;
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> txData = {
|
||||
"fee": fee,
|
||||
"address": address,
|
||||
"recipientAmt": amount,
|
||||
};
|
||||
|
||||
Logging.instance.log("prepare send: $txData", level: LogLevel.Info);
|
||||
return txData;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Error getting fees $e - $s", level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _recoverWalletFromBIP32SeedPhrase({
|
||||
required String mnemonic,
|
||||
required String mnemonicPassphrase,
|
||||
|
@ -572,14 +579,29 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
try {
|
||||
List<Tuple2<SWTransaction.Transaction, SWAddress.Address?>>
|
||||
transactionList = [];
|
||||
|
||||
Page<OperationResponse> payments = await stellarSdk.payments
|
||||
Page<OperationResponse> payments;
|
||||
try {
|
||||
payments = await stellarSdk.payments
|
||||
.forAccount(await getAddressSW())
|
||||
.order(RequestBuilderOrder.DESC)
|
||||
.execute()
|
||||
.onError(
|
||||
(error, stackTrace) => throw ("Could not fetch transactions"));
|
||||
|
||||
.onError((error, stackTrace) => throw error!);
|
||||
} catch (e) {
|
||||
if (e is ErrorResponse &&
|
||||
e.body.contains("The resource at the url requested was not found. "
|
||||
"This usually occurs for one of two reasons: "
|
||||
"The url requested is not valid, or no data in our database "
|
||||
"could be found with the parameters provided.")) {
|
||||
// probably just doesn't have any history yet or whatever stellar needs
|
||||
return;
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Stellar $walletName $walletId failed to fetch transactions",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
for (OperationResponse response in payments.records!) {
|
||||
// PaymentOperationResponse por;
|
||||
if (response is PaymentOperationResponse) {
|
||||
|
@ -717,8 +739,29 @@ class StellarWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
|||
|
||||
Future<void> updateBalance() async {
|
||||
try {
|
||||
AccountResponse accountResponse =
|
||||
await stellarSdk.accounts.account(await getAddressSW());
|
||||
AccountResponse accountResponse;
|
||||
|
||||
try {
|
||||
accountResponse = await stellarSdk.accounts
|
||||
.account(await getAddressSW())
|
||||
.onError((error, stackTrace) => throw error!);
|
||||
} catch (e) {
|
||||
if (e is ErrorResponse &&
|
||||
e.body.contains("The resource at the url requested was not found. "
|
||||
"This usually occurs for one of two reasons: "
|
||||
"The url requested is not valid, or no data in our database "
|
||||
"could be found with the parameters provided.")) {
|
||||
// probably just doesn't have any history yet or whatever stellar needs
|
||||
return;
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Stellar $walletName $walletId failed to fetch transactions",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
for (Balance balance in accountResponse.balances) {
|
||||
switch (balance.assetType) {
|
||||
case Asset.TYPE_NATIVE:
|
||||
|
|
Loading…
Reference in a new issue