Merge pull request #329 from cypherstack/paynyms

Paynyms
This commit is contained in:
Diego Salazar 2023-01-31 11:28:45 -07:00 committed by GitHub
commit 72b823b786
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 126 additions and 28 deletions

BIN
assets/images/unclaimed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 KiB

View file

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4173 5.41699V5.91699H10.9173H14.1257C15.1181 5.91699 15.9173 6.71825 15.9173 7.70866V15.5003C15.9173 16.2377 15.3213 16.8337 14.584 16.8337H5.41732C4.67997 16.8337 4.08398 16.2377 4.08398 15.5003V7.70866C4.08398 6.71866 4.88565 5.91699 5.87565 5.91699H9.08398H9.58398V5.41699V3.58366C9.58398 3.35506 9.77205 3.16699 10.0007 3.16699C10.2292 3.16699 10.4173 3.35506 10.4173 3.58366V5.41699ZM8.16732 15.0837H8.58398H8.66732H9.08398H10.9173H11.334H11.4173H11.834H13.6673H14.1673V14.5837V13.667V13.167H13.6673H11.834H11.4173H11.334H10.9173H9.08398H8.66732H8.58398H8.16732H6.33398H5.83398V13.667V14.5837V15.0837H6.33398H8.16732ZM1.33398 10.0003C1.33398 9.89019 1.37745 9.7852 1.45595 9.70663C1.53524 9.62741 1.64114 9.58366 1.75065 9.58366H2.16732V14.0837H1.75065C1.64023 14.0837 1.53452 14.0398 1.45609 13.9614C1.37774 13.8831 1.33398 13.7775 1.33398 13.667V10.0003ZM5.60482 10.0003C5.60482 10.9095 6.34144 11.6462 7.25065 11.6462C8.15987 11.6462 8.89648 10.9095 8.89648 10.0003C8.89648 9.09111 8.15987 8.35449 7.25065 8.35449C6.34144 8.35449 5.60482 9.09111 5.60482 10.0003ZM11.1048 10.0003C11.1048 10.9101 11.8409 11.6462 12.7507 11.6462C13.6599 11.6462 14.3965 10.9095 14.3965 10.0003C14.3965 9.09111 13.6599 8.35449 12.7507 8.35449C11.8416 8.35449 11.1048 9.09037 11.1048 10.0003ZM18.2507 9.58366C18.3599 9.58366 18.4652 9.62719 18.5445 9.70648C18.6238 9.78578 18.6673 9.89112 18.6673 10.0003V13.667C18.6673 13.7774 18.6235 13.8831 18.5451 13.9616C18.4667 14.0399 18.3612 14.0837 18.2507 14.0837H17.834V9.58366H18.2507Z" fill="#8E9192" stroke="#8E9192"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

3
assets/svg/whirlpool.svg Normal file
View file

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.16811 18.29C4.45149 18.089 3.04304 17.5064 1.84171 16.5006C1.52855 16.2383 1.08929 15.7904 0.868214 15.5078C0.795124 15.4144 0.815885 15.4205 1.16357 15.5943C2.17257 16.0986 3.56529 16.3941 4.67986 16.3404C5.4666 16.3025 6.00361 16.1827 6.16709 16.0087C6.30087 15.8663 6.24663 15.772 5.85013 15.458C4.68271 14.5333 3.91789 13.4633 3.48109 12.1436C2.95876 10.5655 3.03006 8.85291 3.68121 7.33745C3.85982 6.92178 4.22353 6.25056 4.46108 5.89825C5.0569 5.01461 6.02359 4.09702 7.04772 3.443C7.53459 3.13207 8.67134 2.57608 9.28978 2.34638C10.1175 2.03895 11.0493 1.81907 11.9322 1.72278C12.5152 1.6592 13.8654 1.6973 14.3766 1.79177C15.7252 2.04096 16.8058 2.50254 17.8199 3.26249C18.1679 3.52329 18.8273 4.15363 19.0478 4.43636L19.1673 4.58953L18.7556 4.39158C17.6907 3.87949 16.4125 3.60951 15.2969 3.66106C13.9736 3.72218 13.4271 3.9979 13.8908 4.37051C14.4654 4.83219 14.718 5.05501 14.9678 5.32051C16.047 6.46745 16.6696 7.8829 16.8049 9.49648C16.8912 10.527 16.6998 11.6803 16.2805 12.6564C15.6851 14.0423 14.7972 15.1697 13.573 16.0943C13.0338 16.5014 12.6196 16.756 11.9526 17.09C10.795 17.6696 9.68552 18.033 8.49122 18.2239C8.12694 18.2821 6.49683 18.3285 6.16811 18.29ZM10.567 12.7788C11.6493 12.5494 12.5288 11.6694 12.7584 10.586C12.824 10.2766 12.8238 9.72298 12.7584 9.41267C12.6408 8.85789 12.4049 8.43337 11.9758 8.00424C11.3957 7.42417 10.7838 7.17097 9.95841 7.16954C9.16291 7.16743 8.43295 7.4925 7.88801 8.0894C7.39072 8.63413 7.14979 9.25773 7.14979 10.0002C7.14979 10.8011 7.40895 11.4213 7.98385 11.9962C8.40667 12.419 8.83591 12.6598 9.37601 12.7773C9.67249 12.8418 10.2667 12.8425 10.5673 12.7794L10.567 12.7788Z" fill="#8E9192"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -117,7 +117,7 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
),
Image(
image: AssetImage(
Assets.png.stack,
Assets.png.unclaimedPaynym,
),
width: MediaQuery.of(context).size.width / 2,
),

View file

@ -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<TransactionsList> {
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<TransactionsList> {
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<TransactionsList> {
),
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<TransactionsList> {
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<TransactionsList> {
radius = _borderRadiusFirst;
}
final tx = _transactions2[index];
return itemBuilder(context, tx, radius);
return itemBuilder(context, tx, radius, manager.coin);
},
),
);

View file

@ -177,6 +177,14 @@ class _WalletNavigationBarState extends ConsumerState<WalletNavigationBar> {
"Paynym",
style: STextStyles.w600_12(context),
),
const SizedBox(
width: 16,
),
SvgPicture.asset(
Assets.svg.robotHead,
height: 20,
width: 20,
),
],
),
),

View file

@ -213,7 +213,7 @@ class SimplexAPI {
// final Map<String, dynamic> lol =
// Map<String, dynamic>.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;

View file

@ -218,6 +218,19 @@ class BitcoinWallet extends CoinServiceAPI
.findFirst()) ??
await _generateAddressForChain(1, 0, DerivePathTypeExt.primaryFor(coin));
Future<String> get currentChangeAddressP2PKH async =>
(await _currentChangeAddressP2PKH).value;
Future<isar_models.Address> 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<void> 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<void> _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<void> _checkCurrentReceivingAddressesForTransactions() async {
try {
// for (final type in DerivePathType.values) {

View file

@ -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<String, dynamic> 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?,
);
}

View file

@ -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";

View file

@ -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