diff --git a/assets/images/unclaimed.png b/assets/images/unclaimed.png
new file mode 100644
index 000000000..f99d4ab2a
Binary files /dev/null and b/assets/images/unclaimed.png differ
diff --git a/assets/svg/robot-head.svg b/assets/svg/robot-head.svg
new file mode 100644
index 000000000..b6810c227
--- /dev/null
+++ b/assets/svg/robot-head.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/whirlpool.svg b/assets/svg/whirlpool.svg
new file mode 100644
index 000000000..cf075308f
--- /dev/null
+++ b/assets/svg/whirlpool.svg
@@ -0,0 +1,3 @@
+
diff --git a/lib/pages/paynym/paynym_claim_view.dart b/lib/pages/paynym/paynym_claim_view.dart
index 23f9d868e..326983a78 100644
--- a/lib/pages/paynym/paynym_claim_view.dart
+++ b/lib/pages/paynym/paynym_claim_view.dart
@@ -117,7 +117,7 @@ class _PaynymClaimViewState extends ConsumerState {
),
Image(
image: AssetImage(
- Assets.png.stack,
+ Assets.png.unclaimedPaynym,
),
width: MediaQuery.of(context).size.width / 2,
),
diff --git a/lib/pages/wallet_view/sub_widgets/transactions_list.dart b/lib/pages/wallet_view/sub_widgets/transactions_list.dart
index 360b3028b..0c48e69b6 100644
--- a/lib/pages/wallet_view/sub_widgets/transactions_list.dart
+++ b/lib/pages/wallet_view/sub_widgets/transactions_list.dart
@@ -20,6 +20,8 @@ import 'package:stackwallet/widgets/trade_card.dart';
import 'package:stackwallet/widgets/transaction_card.dart';
import 'package:tuple/tuple.dart';
+import '../../../utilities/enums/coin_enum.dart';
+
class TransactionsList extends ConsumerStatefulWidget {
const TransactionsList({
Key? key,
@@ -67,11 +69,18 @@ class _TransactionsListState extends ConsumerState {
BuildContext context,
Transaction tx,
BorderRadius? radius,
+ Coin coin,
) {
final matchingTrades = ref
.read(tradesServiceProvider)
.trades
.where((e) => e.payInTxid == tx.txid || e.payOutTxid == tx.txid);
+
+ final isConfirmed = tx.isConfirmed(
+ ref.watch(
+ widget.managerProvider.select((value) => value.currentHeight)),
+ coin.requiredConfirmations);
+
if (tx.type == TransactionType.outgoing && matchingTrades.isNotEmpty) {
final trade = matchingTrades.first;
return Container(
@@ -84,13 +93,9 @@ class _TransactionsListState extends ConsumerState {
children: [
TransactionCard(
// this may mess with combined firo transactions
- key: Key(tx.txid +
- tx.type.name +
- tx.address.value.toString() +
- ref
- .watch(widget.managerProvider
- .select((value) => value.currentHeight))
- .toString()), //
+ key: isConfirmed
+ ? Key(tx.txid + tx.type.name + tx.address.value.toString())
+ : UniqueKey(), //
transaction: tx,
walletId: widget.walletId,
),
@@ -185,13 +190,9 @@ class _TransactionsListState extends ConsumerState {
),
child: TransactionCard(
// this may mess with combined firo transactions
- key: Key(tx.txid +
- tx.type.name +
- tx.address.value.toString() +
- ref
- .watch(widget.managerProvider
- .select((value) => value.currentHeight))
- .toString()), //
+ key: isConfirmed
+ ? Key(tx.txid + tx.type.name + tx.address.value.toString())
+ : UniqueKey(),
transaction: tx,
walletId: widget.walletId,
),
@@ -263,7 +264,7 @@ class _TransactionsListState extends ConsumerState {
radius = _borderRadiusFirst;
}
final tx = _transactions2[index];
- return itemBuilder(context, tx, radius);
+ return itemBuilder(context, tx, radius, manager.coin);
},
separatorBuilder: (context, index) {
return Container(
@@ -290,7 +291,7 @@ class _TransactionsListState extends ConsumerState {
radius = _borderRadiusFirst;
}
final tx = _transactions2[index];
- return itemBuilder(context, tx, radius);
+ return itemBuilder(context, tx, radius, manager.coin);
},
),
);
diff --git a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart b/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart
index 4e6be9e97..379362dbc 100644
--- a/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart
+++ b/lib/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart
@@ -177,6 +177,14 @@ class _WalletNavigationBarState extends ConsumerState {
"Paynym",
style: STextStyles.w600_12(context),
),
+ const SizedBox(
+ width: 16,
+ ),
+ SvgPicture.asset(
+ Assets.svg.robotHead,
+ height: 20,
+ width: 20,
+ ),
],
),
),
diff --git a/lib/services/buy/simplex/simplex_api.dart b/lib/services/buy/simplex/simplex_api.dart
index 85b4d5d9e..37417fcbf 100644
--- a/lib/services/buy/simplex/simplex_api.dart
+++ b/lib/services/buy/simplex/simplex_api.dart
@@ -213,7 +213,7 @@ class SimplexAPI {
// final Map lol =
// Map.from(jsonArray as Map);
- String? cryptoAmount = jsonArray['digital_money']?['amount'] as String?;
+ double? cryptoAmount = jsonArray['digital_money']?['amount'] as double?;
if (cryptoAmount == null) {
String error = jsonArray['error'] as String;
diff --git a/lib/services/coins/bitcoin/bitcoin_wallet.dart b/lib/services/coins/bitcoin/bitcoin_wallet.dart
index 32c24686b..ad8e9f5da 100644
--- a/lib/services/coins/bitcoin/bitcoin_wallet.dart
+++ b/lib/services/coins/bitcoin/bitcoin_wallet.dart
@@ -218,6 +218,19 @@ class BitcoinWallet extends CoinServiceAPI
.findFirst()) ??
await _generateAddressForChain(1, 0, DerivePathTypeExt.primaryFor(coin));
+ Future get currentChangeAddressP2PKH async =>
+ (await _currentChangeAddressP2PKH).value;
+
+ Future get _currentChangeAddressP2PKH async =>
+ (await db
+ .getAddresses(walletId)
+ .filter()
+ .typeEqualTo(isar_models.AddressType.p2pkh)
+ .subTypeEqualTo(isar_models.AddressSubType.change)
+ .sortByDerivationIndexDesc()
+ .findFirst()) ??
+ await _generateAddressForChain(1, 0, DerivePathType.bip44);
+
@override
Future exit() async {
_hasCalledExit = true;
@@ -1313,13 +1326,14 @@ class BitcoinWallet extends CoinServiceAPI
secureStorage: secureStore,
getMnemonic: () => mnemonic,
getChainHeight: () => chainHeight,
- getCurrentChangeAddress: () => currentChangeAddress,
+ getCurrentChangeAddress: () => currentChangeAddressP2PKH,
estimateTxFee: estimateTxFee,
prepareSend: prepareSend,
getTxCount: getTxCount,
fetchBuildTxData: fetchBuildTxData,
refresh: refresh,
- checkChangeAddressForTransactions: _checkChangeAddressForTransactions,
+ checkChangeAddressForTransactions:
+ _checkP2PKHChangeAddressForTransactions,
addDerivation: addDerivation,
addDerivations: addDerivations,
dustLimitP2PKH: DUST_LIMIT_P2PKH,
@@ -1966,6 +1980,50 @@ class BitcoinWallet extends CoinServiceAPI
}
}
+ Future _checkP2PKHChangeAddressForTransactions() async {
+ try {
+ final currentChange = await _currentChangeAddressP2PKH;
+ final int txCount = await getTxCount(address: currentChange.value);
+ Logging.instance.log(
+ 'Number of txs for current change address $currentChange: $txCount',
+ level: LogLevel.Info);
+
+ if (txCount >= 1 || currentChange.derivationIndex < 0) {
+ // First increment the change index
+ final newChangeIndex = currentChange.derivationIndex + 1;
+
+ // Use new index to derive a new change address
+ final newChangeAddress = await _generateAddressForChain(
+ 1, newChangeIndex, DerivePathType.bip44);
+
+ final existing = await db
+ .getAddresses(walletId)
+ .filter()
+ .valueEqualTo(newChangeAddress.value)
+ .findFirst();
+ if (existing == null) {
+ // Add that new change address
+ await db.putAddress(newChangeAddress);
+ } else {
+ // we need to update the address
+ await db.updateAddress(existing, newChangeAddress);
+ }
+ // keep checking until address with no tx history is set as current
+ await _checkP2PKHChangeAddressForTransactions();
+ }
+ } on SocketException catch (se, s) {
+ Logging.instance.log(
+ "SocketException caught in _checkReceivingAddressForTransactions(${DerivePathType.bip44}): $se\n$s",
+ level: LogLevel.Error);
+ return;
+ } catch (e, s) {
+ Logging.instance.log(
+ "Exception rethrown from _checkReceivingAddressForTransactions(${DerivePathType.bip44}): $e\n$s",
+ level: LogLevel.Error);
+ rethrow;
+ }
+ }
+
Future _checkCurrentReceivingAddressesForTransactions() async {
try {
// for (final type in DerivePathType.values) {
diff --git a/lib/services/mixins/paynym_wallet_interface.dart b/lib/services/mixins/paynym_wallet_interface.dart
index 2292f3ec5..a8354b75f 100644
--- a/lib/services/mixins/paynym_wallet_interface.dart
+++ b/lib/services/mixins/paynym_wallet_interface.dart
@@ -438,11 +438,13 @@ mixin PaynymWalletInterface {
feeRatePerKB: selectedTxFeeRate,
);
- if (feeForNoChange < vSizeForNoChange * 1000) {
- feeForNoChange = vSizeForNoChange * 1000;
- }
- if (feeForWithChange < vSizeForWithChange * 1000) {
- feeForWithChange = vSizeForWithChange * 1000;
+ if (_coin == Coin.dogecoin || _coin == Coin.dogecoinTestNet) {
+ if (feeForNoChange < vSizeForNoChange * 1000) {
+ feeForNoChange = vSizeForNoChange * 1000;
+ }
+ if (feeForWithChange < vSizeForWithChange * 1000) {
+ feeForWithChange = vSizeForWithChange * 1000;
+ }
}
if (satoshisBeingUsed - amountToSend > feeForNoChange + _dustLimitP2PKH) {
@@ -453,7 +455,7 @@ mixin PaynymWalletInterface {
// check estimates are correct and build notification tx
if (changeAmount >= _dustLimitP2PKH &&
satoshisBeingUsed - amountToSend - changeAmount == feeForWithChange) {
- final txn = await _createNotificationTx(
+ var txn = await _createNotificationTx(
targetPaymentCodeString: targetPaymentCodeString,
utxosToUse: utxoObjectsToUse,
utxoSigningData: utxoSigningData,
@@ -462,6 +464,18 @@ mixin PaynymWalletInterface {
int feeBeingPaid = satoshisBeingUsed - amountToSend - changeAmount;
+ // make sure minimum fee is accurate if that is being used
+ if (txn.item2 - feeBeingPaid == 1) {
+ changeAmount -= 1;
+ feeBeingPaid += 1;
+ txn = await _createNotificationTx(
+ targetPaymentCodeString: targetPaymentCodeString,
+ utxosToUse: utxoObjectsToUse,
+ utxoSigningData: utxoSigningData,
+ change: changeAmount,
+ );
+ }
+
Map transactionObject = {
"hex": txn.item1,
"recipientPaynym": targetPaymentCodeString,
@@ -574,6 +588,8 @@ mixin PaynymWalletInterface {
txb.addInput(
utxo.txid,
txPointIndex,
+ null,
+ utxoSigningData[utxo.txid]["output"] as Uint8List,
);
// todo: modify address once segwit support is in our bip47
@@ -592,15 +608,18 @@ mixin PaynymWalletInterface {
txb.sign(
vin: 0,
keyPair: myKeyPair,
+ witnessValue: utxo.value,
+ witnessScript: utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?,
);
// sign rest of possible inputs
- for (var i = 1; i < utxosToUse.length - 1; i++) {
+ for (var i = 1; i < utxosToUse.length; i++) {
final txid = utxosToUse[i].txid;
txb.sign(
vin: i,
keyPair: utxoSigningData[txid]["keyPair"] as btc_dart.ECPair,
- // witnessValue: utxosToUse[i].value,
+ witnessValue: utxosToUse[i].value,
+ witnessScript: utxoSigningData[utxo.txid]["redeemScript"] as Uint8List?,
);
}
diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart
index 5a0427782..5bb7c3edb 100644
--- a/lib/utilities/assets.dart
+++ b/lib/utilities/assets.dart
@@ -194,6 +194,8 @@ class _SVG {
String get exitDesktop => "assets/svg/exit-desktop.svg";
String get keys => "assets/svg/keys.svg";
String get arrowDown => "assets/svg/arrow-down.svg";
+ String get robotHead => "assets/svg/robot-head.svg";
+ String get whirlPool => "assets/svg/whirlpool.svg";
String get ellipse1 => "assets/svg/Ellipse-43.svg";
String get ellipse2 => "assets/svg/Ellipse-42.svg";
@@ -262,6 +264,7 @@ class _PNG {
const _PNG();
String get stack => "assets/images/stack.png";
+ String get unclaimedPaynym => "assets/images/unclaimed.png";
String get splash => "assets/images/splash.png";
String get monero => "assets/images/monero.png";
diff --git a/pubspec.yaml b/pubspec.yaml
index 5ab5c8b80..fb8b264d4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -205,6 +205,7 @@ flutter:
- assets/svg/circle-check.svg
- assets/svg/clipboard.svg
- assets/images/stack.png
+ - assets/images/unclaimed.png
- assets/images/monero.png
- assets/images/wownero.png
- assets/images/firo.png
@@ -309,6 +310,8 @@ flutter:
- assets/svg/plus-circle.svg
- assets/svg/circle-plus-filled.svg
- assets/svg/configuration.svg
+ - assets/svg/robot-head.svg
+ - assets/svg/whirlpool.svg
# coin icons
- assets/svg/coin_icons/Bitcoin.svg
- assets/svg/coin_icons/Litecoin.svg