Merge pull request from cypherstack/gradle_ndk

Gradle ndk
This commit is contained in:
julian-CStack 2025-03-27 11:01:47 -06:00 committed by GitHub
commit 02fec3d581
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 817 additions and 1013 deletions

View file

@ -1,3 +1,3 @@
org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true

View file

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip

View file

@ -18,7 +18,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version '8.6.0' apply false
id "com.android.application" version '8.7.0' apply false
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}

@ -1 +1 @@
Subproject commit 8830be2ba661828d743be12df6f33d560448ed6a
Subproject commit 238455f2b3fe39564cc617ed0ea45f22971aa644

@ -1 +1 @@
Subproject commit 89f05ee42754f80da036ddcf31c7b1e1dc3b4a83
Subproject commit 30bc004bd7cadd635e943d29033a8d261cbc1eda

View file

@ -72,8 +72,8 @@ Install [Rust](https://www.rust-lang.org/tools/install) via [rustup.rs](https://
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.bashrc
rustup install 1.67.1 1.71.0 1.72.0 1.73.0
rustup default 1.67.1
rustup install 1.85.1
rustup default 1.85.1
cargo install cargo-ndk --version 2.12.7 --locked
```
@ -209,12 +209,12 @@ brew install brotli cairo coreutils gdbm gettext glib gmp libevent libidn2 libng
```
<!-- TODO: determine which of the above list are not needed at all. -->
Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.67.1 and 1.72.0 and `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s):
Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchain 1.85.1 and `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s):
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.bashrc
rustup install 1.67.1 1.71.0 1.72.0 1.73.0
rustup default 1.67.1
rustup install 1.85.1
rustup default 1.85.1
cargo install cargo-ndk --version 2.12.7 --locked
cargo install cbindgen cargo-lipo
rustup target add aarch64-apple-ios aarch64-apple-darwin
@ -306,8 +306,8 @@ Run `flutter doctor` in PowerShell to confirm its installation.
### Rust
Install [Rust](https://www.rust-lang.org/tools/install) on the Windows host (not in WSL2). Download the installer from [rustup.rs](https://rustup.rs), make sure it works on the commandline (you may need to open a new terminal), and install the following versions:
```
rustup install 1.67.1 1.71.0 1.72.0 1.73.0
rustup default 1.67.1
rustup install 1.85.1
rustup default 1.85.1
cargo install cargo-ndk --version 2.12.7 --locked
```

View file

@ -41,11 +41,7 @@ String nameSaltKeyBuilder(String txid, String walletId, int txPos) {
}
String encodeNameSaltData(String name, String salt, String value) =>
jsonEncode({
"name": name,
"salt": salt,
"value": value,
});
jsonEncode({"name": name, "salt": salt, "value": value});
({String salt, String name, String value}) decodeNameSaltData(String value) {
try {
@ -76,25 +72,26 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
@override
Future<List<Address>> fetchAddressesForElectrumXScan() async {
final allAddresses = await mainDB
.getAddresses(walletId)
.filter()
.not()
.group(
(q) => q
.typeEqualTo(AddressType.nonWallet)
.or()
.subTypeEqualTo(AddressSubType.nonWallet),
)
.findAll();
final allAddresses =
await mainDB
.getAddresses(walletId)
.filter()
.not()
.group(
(q) => q
.typeEqualTo(AddressType.nonWallet)
.or()
.subTypeEqualTo(AddressSubType.nonWallet),
)
.findAll();
return allAddresses;
}
// ===========================================================================
// ===========================================================================
@override
Future<({String? blockedReason, bool blocked, String? utxoLabel})>
checkBlockUTXO(
checkBlockUTXO(
Map<String, dynamic> jsonUTXO,
String? scriptPubKeyHex,
Map<String, dynamic> jsonTX,
@ -108,9 +105,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
}
@override
Future<UTXO> parseUTXO({
required Map<String, dynamic> jsonUTXO,
}) async {
Future<UTXO> parseUTXO({required Map<String, dynamic> jsonUTXO}) async {
final txn = await electrumXCachedClient.getTransaction(
txHash: jsonUTXO["tx_hash"] as String,
verbose: true,
@ -136,7 +131,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
if (output["n"] == vout) {
utxoOwnerAddress =
output["scriptPubKey"]?["addresses"]?[0] as String? ??
output["scriptPubKey"]?["address"] as String?;
output["scriptPubKey"]?["address"] as String?;
// check for nameOp
if (output["scriptPubKey"]?["nameOp"] != null) {
@ -145,19 +140,15 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
blockReason = "Contains name";
try {
final rawNameOP = (output["scriptPubKey"]["nameOp"] as Map)
.cast<String, dynamic>();
final rawNameOP =
(output["scriptPubKey"]["nameOp"] as Map)
.cast<String, dynamic>();
otherDataString = jsonEncode({
UTXOOtherDataKeys.nameOpData: jsonEncode(rawNameOP),
});
final nameOp = OpNameData(
rawNameOP,
jsonUTXO["height"] as int,
);
Logging.instance.i(
"nameOp:\n$nameOp",
);
final nameOp = OpNameData(rawNameOP, jsonUTXO["height"] as int);
Logging.instance.i("nameOp:\n$nameOp");
switch (nameOp.op) {
case OpName.nameNew:
@ -193,7 +184,8 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
name: label ?? "",
isBlocked: shouldBlock,
blockedReason: blockReason,
isCoinbase: txn["is_coinbase"] as bool? ??
isCoinbase:
txn["is_coinbase"] as bool? ??
txn["is-coinbase"] as bool? ??
txn["iscoinbase"] as bool? ??
isCoinbase,
@ -231,30 +223,34 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
await fetchAddressesForElectrumXScan();
// Separate receiving and change addresses.
final Set<String> receivingAddresses = allAddressesOld
.where((e) => e.subType == AddressSubType.receiving)
.map((e) => e.value)
.toSet();
final Set<String> changeAddresses = allAddressesOld
.where((e) => e.subType == AddressSubType.change)
.map((e) => e.value)
.toSet();
final Set<String> receivingAddresses =
allAddressesOld
.where((e) => e.subType == AddressSubType.receiving)
.map((e) => e.value)
.toSet();
final Set<String> changeAddresses =
allAddressesOld
.where((e) => e.subType == AddressSubType.change)
.map((e) => e.value)
.toSet();
// Remove duplicates.
final allAddressesSet = {...receivingAddresses, ...changeAddresses};
// Fetch history from ElectrumX.
final List<Map<String, dynamic>> allTxHashes =
await fetchHistory(allAddressesSet);
final List<Map<String, dynamic>> allTxHashes = await fetchHistory(
allAddressesSet,
);
// Only parse new txs (not in db yet).
final List<Map<String, dynamic>> allTransactions = [];
for (final txHash in allTxHashes) {
// Check for duplicates by searching for tx by tx_hash in db.
final storedTx = await mainDB.isar.transactionV2s
.where()
.txidWalletIdEqualTo(txHash["tx_hash"] as String, walletId)
.findFirst();
final storedTx =
await mainDB.isar.transactionV2s
.where()
.txidWalletIdEqualTo(txHash["tx_hash"] as String, walletId)
.findFirst();
if (storedTx == null ||
storedTx.height == null ||
@ -267,8 +263,9 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
);
// Only tx to list once.
if (allTransactions
.indexWhere((e) => e["txid"] == tx["txid"] as String) ==
if (allTransactions.indexWhere(
(e) => e["txid"] == tx["txid"] as String,
) ==
-1) {
tx["height"] = txHash["height"];
allTransactions.add(tx);
@ -418,7 +415,8 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
txid: txData["txid"] as String,
height: txData["height"] as int?,
version: txData["version"] as int,
timestamp: txData["blocktime"] as int? ??
timestamp:
txData["blocktime"] as int? ??
DateTime.timestamp().millisecondsSinceEpoch ~/ 1000,
inputs: List.unmodifiable(inputs),
outputs: List.unmodifiable(outputs),
@ -456,10 +454,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
final data = decodeNameSaltData(encoded);
if (data.name == name) {
return (
data: null,
nameState: NameState.unavailable,
);
return (data: null, nameState: NameState.unavailable);
}
}
}
@ -485,9 +480,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
opNameData = OpNameData.fromTx(txMap, txHeight);
final isExpired = opNameData.expired(await chainHeight);
Logging.instance.i(
"Name $opNameData \nis expired = $isExpired",
);
Logging.instance.i("Name $opNameData \nis expired = $isExpired");
available = isExpired;
} catch (_) {
available = false; // probably
@ -508,23 +501,22 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
/// Must be called in refresh() AFTER the wallet's UTXOs have been updated!
Future<void> checkAutoRegisterNameNewOutputs() async {
Logging.instance.t(
"$walletId checkAutoRegisterNameNewOutputs()",
);
Logging.instance.t("$walletId checkAutoRegisterNameNewOutputs()");
try {
final currentHeight = await chainHeight;
// not ideal filtering
final utxos = await mainDB
.getUTXOs(walletId)
.filter()
.otherDataIsNotNull()
.and()
.blockHeightIsNotNull()
.and()
.blockHeightGreaterThan(0)
.and()
.blockHeightLessThan(currentHeight - kNameWaitBlocks)
.findAll();
final utxos =
await mainDB
.getUTXOs(walletId)
.filter()
.otherDataIsNotNull()
.and()
.blockHeightIsNotNull()
.and()
.blockHeightGreaterThan(0)
.and()
.blockHeightLessThan(currentHeight - kNameWaitBlocks)
.findAll();
Logging.instance.t(
"_unknownNameNewOutputs(count=${_unknownNameNewOutputs.length})"
@ -539,9 +531,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
for (final utxo in utxos) {
final nameOp = getOpNameDataFrom(utxo);
if (nameOp != null) {
Logging.instance.t(
"Found OpName: $nameOp\n\nIN UTXO: $utxo",
);
Logging.instance.t("Found OpName: $nameOp\n\nIN UTXO: $utxo");
if (nameOp.op == OpName.nameNew) {
// at this point we should have an unspent UTXO that is at least
@ -646,14 +636,10 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
switch (txData.opNameState!.type) {
case OpName.nameNew:
assert(
nameAmount.raw == BigInt.from(kNameNewAmountSats),
);
assert(nameAmount.raw == BigInt.from(kNameNewAmountSats));
break;
case OpName.nameFirstUpdate || OpName.nameUpdate:
assert(
nameAmount.raw == BigInt.from(kNameAmountSats),
);
assert(nameAmount.raw == BigInt.from(kNameAmountSats));
break;
}
}
@ -671,9 +657,10 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
);
// TODO: [prio=high]: check this opt in rbf
final sequence = this is RbfInterface && (this as RbfInterface).flagOptInRBF
? 0xffffffff - 10
: 0xffffffff - 1;
final sequence =
this is RbfInterface && (this as RbfInterface).flagOptInRBF
? 0xffffffff - 10
: 0xffffffff - 1;
// Add transaction inputs
for (int i = 0; i < utxoSigningData.length; i++) {
@ -683,10 +670,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
txid.toUint8ListFromHex.reversed.toList(),
);
final prevOutpoint = coinlib.OutPoint(
hash,
utxoSigningData[i].utxo.vout,
);
final prevOutpoint = coinlib.OutPoint(hash, utxoSigningData[i].utxo.vout);
final prevOutput = coinlib.Output.fromAddress(
BigInt.from(utxoSigningData[i].utxo.value),
@ -746,9 +730,10 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
txid: utxoSigningData[i].utxo.txid,
vout: utxoSigningData[i].utxo.vout,
),
addresses: utxoSigningData[i].utxo.address == null
? []
: [utxoSigningData[i].utxo.address!],
addresses:
utxoSigningData[i].utxo.address == null
? []
: [utxoSigningData[i].utxo.address!],
valueStringSats: utxoSigningData[i].utxo.value.toString(),
witness: null,
innerRedeemScriptAsm: null,
@ -803,10 +788,9 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
OutputV2.isarCantDoRequiredInDefaultConstructor(
scriptPubKeyHex: "000000",
valueStringSats: txData.recipients![i].amount.raw.toString(),
addresses: [
txData.recipients![i].address.toString(),
],
walletOwns: (await mainDB.isar.addresses
addresses: [txData.recipients![i].address.toString()],
walletOwns:
(await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
@ -822,22 +806,33 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
// Sign the transaction accordingly
for (int i = 0; i < utxoSigningData.length; i++) {
final value = BigInt.from(utxoSigningData[i].utxo.value);
coinlib.ECPrivateKey key = utxoSigningData[i].keyPair!.privateKey;
final key = utxoSigningData[i].keyPair!.privateKey;
if (clTx.inputs[i] is coinlib.TaprootKeyInput) {
final taproot = coinlib.Taproot(
internalKey: utxoSigningData[i].keyPair!.publicKey,
);
key = taproot.tweakPrivateKey(key);
clTx = clTx.signTaproot(
inputN: i,
key: taproot.tweakPrivateKey(key),
prevOuts: prevOuts,
);
} else if (clTx.inputs[i] is coinlib.LegacyWitnessInput) {
clTx = clTx.signLegacyWitness(inputN: i, key: key, value: value);
} else if (clTx.inputs[i] is coinlib.LegacyInput) {
clTx = clTx.signLegacy(inputN: i, key: key);
} else if (clTx.inputs[i] is coinlib.TaprootSingleScriptSigInput) {
clTx = clTx.signTaprootSingleScriptSig(
inputN: i,
key: key,
prevOuts: prevOuts,
);
} else {
throw Exception(
"Unable to sign input of type ${clTx.inputs[i].runtimeType}",
);
}
clTx = clTx.sign(
inputN: i,
value: value,
key: key,
prevOuts: prevOuts,
);
}
} catch (e, s) {
Logging.instance.e(
@ -879,17 +874,13 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
);
}
Future<TxData> prepareNameSend({
required TxData txData,
}) async {
Future<TxData> prepareNameSend({required TxData txData}) async {
try {
if (txData.amount == null) {
throw Exception("No recipients in attempted transaction!");
}
Logging.instance.t(
"prepareNameSend called with TxData:\n\n$txData",
);
Logging.instance.t("prepareNameSend called with TxData:\n\n$txData");
final feeRateType = txData.feeRateType;
final customSatsPerVByte = txData.satsPerVByte;
@ -944,20 +935,17 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
}
final result = await coinSelectionName(
txData: txData.copyWith(
feeRateAmount: rate,
),
txData: txData.copyWith(feeRateAmount: rate),
utxos: utxos?.toList(),
coinControl: coinControl,
);
Logging.instance.d(
"prepare send: $result",
);
Logging.instance.d("prepare send: $result");
if (result.fee!.raw.toInt() < result.vSize!) {
throw Exception(
"Error in fee calculation: Transaction fee (${result.fee!.raw.toInt()}) cannot "
"be less than vSize (${result.vSize})");
"Error in fee calculation: Transaction fee (${result.fee!.raw.toInt()}) cannot "
"be less than vSize (${result.vSize})",
);
}
return result;
@ -1028,19 +1016,20 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
final canCPFP = this is CpfpInterface && coinControl;
final spendableOutputs = availableOutputs
.where(
(e) =>
!e.isBlocked &&
(e.used != true) &&
(canCPFP ||
e.isConfirmed(
currentChainHeight,
cryptoCurrency.minConfirms,
cryptoCurrency.minCoinbaseConfirms,
)),
)
.toList();
final spendableOutputs =
availableOutputs
.where(
(e) =>
!e.isBlocked &&
(e.used != true) &&
(canCPFP ||
e.isConfirmed(
currentChainHeight,
cryptoCurrency.minConfirms,
cryptoCurrency.minCoinbaseConfirms,
)),
)
.toList();
if (coinControl) {
if (spendableOutputs.length < availableOutputs.length) {
@ -1050,8 +1039,9 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
} else {
// sort spendable by age (oldest first)
spendableOutputs.sort(
(a, b) => (b.blockTime ?? currentChainHeight)
.compareTo((a.blockTime ?? currentChainHeight)),
(a, b) => (b.blockTime ?? currentChainHeight).compareTo(
(a.blockTime ?? currentChainHeight),
),
);
}
@ -1061,8 +1051,10 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
spendableOutputs.insert(0, txData.opNameState!.output!);
}
final spendableSatoshiValue =
spendableOutputs.fold(BigInt.zero, (p, e) => p + BigInt.from(e.value));
final spendableSatoshiValue = spendableOutputs.fold(
BigInt.zero,
(p, e) => p + BigInt.from(e.value),
);
if (spendableSatoshiValue < satoshiAmountToSend) {
throw Exception("Insufficient balance");
@ -1082,21 +1074,24 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
final List<UTXO> utxoObjectsToUse = [];
if (!coinControl) {
for (int i = 0;
satoshisBeingUsed < satoshiAmountToSend &&
i < spendableOutputs.length;
i++) {
for (
int i = 0;
satoshisBeingUsed < satoshiAmountToSend && i < spendableOutputs.length;
i++
) {
utxoObjectsToUse.add(spendableOutputs[i]);
satoshisBeingUsed += BigInt.from(spendableOutputs[i].value);
inputsBeingConsumed += 1;
}
for (int i = 0;
i < additionalOutputs &&
inputsBeingConsumed < spendableOutputs.length;
i++) {
for (
int i = 0;
i < additionalOutputs && inputsBeingConsumed < spendableOutputs.length;
i++
) {
utxoObjectsToUse.add(spendableOutputs[inputsBeingConsumed]);
satoshisBeingUsed +=
BigInt.from(spendableOutputs[inputsBeingConsumed].value);
satoshisBeingUsed += BigInt.from(
spendableOutputs[inputsBeingConsumed].value,
);
inputsBeingConsumed += 1;
}
} else {
@ -1120,17 +1115,17 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
final int vSizeForOneOutput;
try {
vSizeForOneOutput = (await _createNameTx(
utxoSigningData: utxoSigningData,
isForFeeCalcPurposesOnly: true,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[satoshisBeingUsed],
),
),
))
.vSize!;
vSizeForOneOutput =
(await _createNameTx(
utxoSigningData: utxoSigningData,
isForFeeCalcPurposesOnly: true,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[satoshisBeingUsed],
),
),
)).vSize!;
} catch (e, s) {
Logging.instance.e("vSizeForOneOutput: $e", error: e, stackTrace: s);
rethrow;
@ -1141,23 +1136,20 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
BigInt maxBI(BigInt a, BigInt b) => a > b ? a : b;
try {
vSizeForTwoOutPuts = (await _createNameTx(
utxoSigningData: utxoSigningData,
isForFeeCalcPurposesOnly: true,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress, (await getCurrentChangeAddress())!.value],
[
satoshiAmountToSend,
maxBI(
BigInt.zero,
satoshisBeingUsed - satoshiAmountToSend,
vSizeForTwoOutPuts =
(await _createNameTx(
utxoSigningData: utxoSigningData,
isForFeeCalcPurposesOnly: true,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress, (await getCurrentChangeAddress())!.value],
[
satoshiAmountToSend,
maxBI(BigInt.zero, satoshisBeingUsed - satoshiAmountToSend),
],
),
],
),
),
))
.vSize!;
),
)).vSize!;
} catch (e, s) {
Logging.instance.e("vSizeForTwoOutPuts: $e", error: e, stackTrace: s);
rethrow;
@ -1168,18 +1160,18 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
satsPerVByte != null
? (satsPerVByte * vSizeForOneOutput)
: estimateTxFee(
vSize: vSizeForOneOutput,
feeRatePerKB: selectedTxFeeRate,
),
vSize: vSizeForOneOutput,
feeRatePerKB: selectedTxFeeRate,
),
);
// Assume 2 outputs, one for recipient and one for change
final feeForTwoOutputs = BigInt.from(
satsPerVByte != null
? (satsPerVByte * vSizeForTwoOutPuts)
: estimateTxFee(
vSize: vSizeForTwoOutPuts,
feeRatePerKB: selectedTxFeeRate,
),
vSize: vSizeForTwoOutPuts,
feeRatePerKB: selectedTxFeeRate,
),
);
Logging.instance.d(
@ -1250,12 +1242,14 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
recipientsArray.add(newChangeAddress);
recipientsAmtArray.add(changeOutputSize);
Logging.instance.d('2 outputs in tx'
'\nInput size: $satoshisBeingUsed'
'\nRecipient output size: $satoshiAmountToSend'
'\nChange Output Size: $changeOutputSize'
'\nDifference (fee being paid): $feeBeingPaid sats'
'\nEstimated fee: $feeForTwoOutputs');
Logging.instance.d(
'2 outputs in tx'
'\nInput size: $satoshisBeingUsed'
'\nRecipient output size: $satoshiAmountToSend'
'\nChange Output Size: $changeOutputSize'
'\nDifference (fee being paid): $feeBeingPaid sats'
'\nEstimated fee: $feeForTwoOutputs',
);
TxData txnData = await _createNameTx(
utxoSigningData: utxoSigningData,
@ -1305,9 +1299,7 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
} else {
// Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize
// is smaller than or equal to cryptoCurrency.dustLimit. Revert to single output transaction.
Logging.instance.d(
'Reverting to 1 output in tx',
);
Logging.instance.d('Reverting to 1 output in tx');
return await _singleOutputTxn();
}
@ -1365,7 +1357,4 @@ class NamecoinWallet<T extends ElectrumXCurrencyInterface>
}
}
enum NameState {
available,
unavailable;
}
enum NameState { available, unavailable }

View file

@ -36,7 +36,8 @@ import 'rbf_interface.dart';
import 'view_only_option_interface.dart';
mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
on Bip39HDWallet<T> implements ViewOnlyOptionInterface<T> {
on Bip39HDWallet<T>
implements ViewOnlyOptionInterface<T> {
late ElectrumXClient electrumXClient;
late CachedElectrumXClient electrumXCachedClient;
@ -54,9 +55,10 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
try {
_serverVersion ??= _parseServerVersion(
(await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 2)))["server_version"] as String,
(await electrumXClient.getServerFeatures().timeout(
const Duration(seconds: 2),
))["server_version"]
as String,
);
} catch (_) {
// ignore failure as it doesn't matter
@ -74,32 +76,28 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
Future<List<({String address, Amount amount, bool isChange})>>
helperRecipientsConvert(
List<String> addrs,
List<BigInt> satValues,
) async {
helperRecipientsConvert(List<String> addrs, List<BigInt> satValues) async {
final List<({String address, Amount amount, bool isChange})> results = [];
for (int i = 0; i < addrs.length; i++) {
results.add(
(
address: addrs[i],
amount: Amount(
rawValue: satValues[i],
fractionDigits: cryptoCurrency.fractionDigits,
),
isChange: (await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(AddressSubType.change)
.and()
.valueEqualTo(addrs[i])
.valueProperty()
.findFirst()) !=
null
results.add((
address: addrs[i],
amount: Amount(
rawValue: satValues[i],
fractionDigits: cryptoCurrency.fractionDigits,
),
);
isChange:
(await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(AddressSubType.change)
.and()
.valueEqualTo(addrs[i])
.valueProperty()
.findFirst()) !=
null,
));
}
return results;
@ -133,21 +131,24 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
final canCPFP = this is CpfpInterface && coinControl;
final spendableOutputs = availableOutputs
.where(
(e) =>
!e.isBlocked &&
(e.used != true) &&
(canCPFP ||
e.isConfirmed(
currentChainHeight,
cryptoCurrency.minConfirms,
cryptoCurrency.minCoinbaseConfirms,
)),
)
.toList();
final spendableSatoshiValue =
spendableOutputs.fold(BigInt.zero, (p, e) => p + BigInt.from(e.value));
final spendableOutputs =
availableOutputs
.where(
(e) =>
!e.isBlocked &&
(e.used != true) &&
(canCPFP ||
e.isConfirmed(
currentChainHeight,
cryptoCurrency.minConfirms,
cryptoCurrency.minCoinbaseConfirms,
)),
)
.toList();
final spendableSatoshiValue = spendableOutputs.fold(
BigInt.zero,
(p, e) => p + BigInt.from(e.value),
);
if (spendableSatoshiValue < satoshiAmountToSend) {
throw Exception("Insufficient balance");
@ -165,45 +166,41 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
} else {
// sort spendable by age (oldest first)
spendableOutputs.sort(
(a, b) => (b.blockTime ?? currentChainHeight)
.compareTo((a.blockTime ?? currentChainHeight)),
(a, b) => (b.blockTime ?? currentChainHeight).compareTo(
(a.blockTime ?? currentChainHeight),
),
);
}
Logging.instance.d(
"spendableOutputs.length: ${spendableOutputs.length}",
);
Logging.instance.d(
"availableOutputs.length: ${availableOutputs.length}",
);
Logging.instance.d("spendableOutputs.length: ${spendableOutputs.length}");
Logging.instance.d("availableOutputs.length: ${availableOutputs.length}");
Logging.instance.d("spendableOutputs: $spendableOutputs");
Logging.instance.d(
"spendableSatoshiValue: $spendableSatoshiValue",
);
Logging.instance.d(
"satoshiAmountToSend: $satoshiAmountToSend",
);
Logging.instance.d("spendableSatoshiValue: $spendableSatoshiValue");
Logging.instance.d("satoshiAmountToSend: $satoshiAmountToSend");
BigInt satoshisBeingUsed = BigInt.zero;
int inputsBeingConsumed = 0;
final List<UTXO> utxoObjectsToUse = [];
if (!coinControl) {
for (var i = 0;
satoshisBeingUsed < satoshiAmountToSend &&
i < spendableOutputs.length;
i++) {
for (
var i = 0;
satoshisBeingUsed < satoshiAmountToSend && i < spendableOutputs.length;
i++
) {
utxoObjectsToUse.add(spendableOutputs[i]);
satoshisBeingUsed += BigInt.from(spendableOutputs[i].value);
inputsBeingConsumed += 1;
}
for (int i = 0;
i < additionalOutputs &&
inputsBeingConsumed < spendableOutputs.length;
i++) {
for (
int i = 0;
i < additionalOutputs && inputsBeingConsumed < spendableOutputs.length;
i++
) {
utxoObjectsToUse.add(spendableOutputs[inputsBeingConsumed]);
satoshisBeingUsed +=
BigInt.from(spendableOutputs[inputsBeingConsumed].value);
satoshisBeingUsed += BigInt.from(
spendableOutputs[inputsBeingConsumed].value,
);
inputsBeingConsumed += 1;
}
} else {
@ -213,9 +210,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
Logging.instance.d("satoshisBeingUsed: $satoshisBeingUsed");
Logging.instance.d(
"inputsBeingConsumed: $inputsBeingConsumed",
);
Logging.instance.d("inputsBeingConsumed: $inputsBeingConsumed");
Logging.instance.d('utxoObjectsToUse: $utxoObjectsToUse');
// numberOfOutputs' length must always be equal to that of recipientsArray and recipientsAmtArray
@ -245,16 +240,16 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
final int vSizeForOneOutput;
try {
vSizeForOneOutput = (await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[satoshisBeingUsed - BigInt.one],
),
),
))
.vSize!;
vSizeForOneOutput =
(await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[satoshisBeingUsed - BigInt.one],
),
),
)).vSize!;
} catch (e, s) {
Logging.instance.e("vSizeForOneOutput: $e", error: e, stackTrace: s);
rethrow;
@ -265,22 +260,22 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
BigInt maxBI(BigInt a, BigInt b) => a > b ? a : b;
try {
vSizeForTwoOutPuts = (await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress, (await getCurrentChangeAddress())!.value],
[
satoshiAmountToSend,
maxBI(
BigInt.zero,
satoshisBeingUsed - (satoshiAmountToSend + BigInt.one),
vSizeForTwoOutPuts =
(await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress, (await getCurrentChangeAddress())!.value],
[
satoshiAmountToSend,
maxBI(
BigInt.zero,
satoshisBeingUsed - (satoshiAmountToSend + BigInt.one),
),
],
),
],
),
),
))
.vSize!;
),
)).vSize!;
} catch (e, s) {
Logging.instance.e("vSizeForTwoOutPuts: $e", error: e, stackTrace: s);
rethrow;
@ -291,42 +286,30 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
satsPerVByte != null
? (satsPerVByte * vSizeForOneOutput)
: estimateTxFee(
vSize: vSizeForOneOutput,
feeRatePerKB: selectedTxFeeRate,
),
vSize: vSizeForOneOutput,
feeRatePerKB: selectedTxFeeRate,
),
);
// Assume 2 outputs, one for recipient and one for change
final feeForTwoOutputs = BigInt.from(
satsPerVByte != null
? (satsPerVByte * vSizeForTwoOutPuts)
: estimateTxFee(
vSize: vSizeForTwoOutPuts,
feeRatePerKB: selectedTxFeeRate,
),
vSize: vSizeForTwoOutPuts,
feeRatePerKB: selectedTxFeeRate,
),
);
Logging.instance.d(
"feeForTwoOutputs: $feeForTwoOutputs",
);
Logging.instance.d(
"feeForOneOutput: $feeForOneOutput",
);
Logging.instance.d("feeForTwoOutputs: $feeForTwoOutputs");
Logging.instance.d("feeForOneOutput: $feeForOneOutput");
final difference = satoshisBeingUsed - satoshiAmountToSend;
Future<TxData> singleOutputTxn() async {
Logging.instance.d(
'Input size: $satoshisBeingUsed',
);
Logging.instance.d(
'Recipient output size: $satoshiAmountToSend',
);
Logging.instance.d(
'Fee being paid: $difference sats',
);
Logging.instance.d(
'Estimated fee: $feeForOneOutput',
);
Logging.instance.d('Input size: $satoshisBeingUsed');
Logging.instance.d('Recipient output size: $satoshiAmountToSend');
Logging.instance.d('Fee being paid: $difference sats');
Logging.instance.d('Estimated fee: $feeForOneOutput');
final txnData = await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
@ -406,9 +389,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
recipientsAmtArray.removeLast();
recipientsAmtArray.add(changeOutputSize);
Logging.instance.d(
'Adjusted Input size: $satoshisBeingUsed',
);
Logging.instance.d('Adjusted Input size: $satoshisBeingUsed');
Logging.instance.d(
'Adjusted Recipient output size: $satoshiAmountToSend',
);
@ -418,9 +399,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
Logging.instance.d(
'Adjusted Difference (fee being paid): $feeBeingPaid sats',
);
Logging.instance.d(
'Adjusted Estimated fee: $feeForTwoOutputs',
);
Logging.instance.d('Adjusted Estimated fee: $feeForTwoOutputs');
txnData = await buildTransaction(
utxoSigningData: utxoSigningData,
@ -443,9 +422,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
} else {
// Something went wrong here. It either overshot or undershot the estimated fee amount or the changeOutputSize
// is smaller than or equal to cryptoCurrency.dustLimit. Revert to single output transaction.
Logging.instance.d(
'Reverting to 1 output in tx',
);
Logging.instance.d('Reverting to 1 output in tx');
return await singleOutputTxn();
}
@ -466,36 +443,28 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}) async {
Logging.instance.d("Attempting to send all $cryptoCurrency");
if (txData.recipients!.length != 1) {
throw Exception(
"Send all to more than one recipient not yet supported",
);
throw Exception("Send all to more than one recipient not yet supported");
}
final int vSizeForOneOutput = (await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[satoshisBeingUsed - BigInt.one],
),
),
))
.vSize!;
final int vSizeForOneOutput =
(await buildTransaction(
utxoSigningData: utxoSigningData,
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[satoshisBeingUsed - BigInt.one],
),
),
)).vSize!;
BigInt feeForOneOutput = BigInt.from(
satsPerVByte != null
? (satsPerVByte * vSizeForOneOutput)
: estimateTxFee(
vSize: vSizeForOneOutput,
feeRatePerKB: feeRatePerKB,
),
: estimateTxFee(vSize: vSizeForOneOutput, feeRatePerKB: feeRatePerKB),
);
if (satsPerVByte == null) {
final roughEstimate = roughFeeEstimate(
utxoSigningData.length,
1,
feeRatePerKB,
).raw;
final roughEstimate =
roughFeeEstimate(utxoSigningData.length, 1, feeRatePerKB).raw;
if (feeForOneOutput < roughEstimate) {
feeForOneOutput = roughEstimate;
}
@ -511,10 +480,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
final data = await buildTransaction(
txData: txData.copyWith(
recipients: await helperRecipientsConvert(
[recipientAddress],
[amount],
),
recipients: await helperRecipientsConvert([recipientAddress], [amount]),
),
utxoSigningData: utxoSigningData,
);
@ -528,23 +494,19 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
);
}
Future<List<SigningData>> fetchBuildTxData(
List<UTXO> utxosToUse,
) async {
Future<List<SigningData>> fetchBuildTxData(List<UTXO> utxosToUse) async {
// return data
final List<SigningData> signingData = [];
try {
// Populating the addresses to check
for (var i = 0; i < utxosToUse.length; i++) {
final derivePathType =
cryptoCurrency.addressType(address: utxosToUse[i].address!);
final derivePathType = cryptoCurrency.addressType(
address: utxosToUse[i].address!,
);
signingData.add(
SigningData(
derivePathType: derivePathType,
utxo: utxosToUse[i],
),
SigningData(derivePathType: derivePathType, utxo: utxosToUse[i]),
);
}
@ -564,9 +526,9 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
final privateKey = await (this as PaynymInterface)
.getPrivateKeyForPaynymReceivingAddress(
paymentCodeString: code!,
index: address.derivationIndex,
);
paymentCodeString: code!,
index: address.derivationIndex,
);
keys = coinlib.HDPrivateKey.fromKeyAndChainCode(
coinlib.ECPrivateKey.fromHex(privateKey.toHex),
@ -594,11 +556,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
return signingData;
} catch (e, s) {
Logging.instance.e(
"fetchBuildTxData() threw",
error: e,
stackTrace: s,
);
Logging.instance.e("fetchBuildTxData() threw", error: e, stackTrace: s);
rethrow;
}
}
@ -623,9 +581,10 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
);
// TODO: [prio=high]: check this opt in rbf
final sequence = this is RbfInterface && (this as RbfInterface).flagOptInRBF
? 0xffffffff - 10
: 0xffffffff - 1;
final sequence =
this is RbfInterface && (this as RbfInterface).flagOptInRBF
? 0xffffffff - 10
: 0xffffffff - 1;
// Add transaction inputs
for (var i = 0; i < utxoSigningData.length; i++) {
@ -635,10 +594,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
txid.toUint8ListFromHex.reversed.toList(),
);
final prevOutpoint = coinlib.OutPoint(
hash,
utxoSigningData[i].utxo.vout,
);
final prevOutpoint = coinlib.OutPoint(hash, utxoSigningData[i].utxo.vout);
final prevOutput = coinlib.Output.fromAddress(
BigInt.from(utxoSigningData[i].utxo.value),
@ -699,9 +655,10 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
txid: utxoSigningData[i].utxo.txid,
vout: utxoSigningData[i].utxo.vout,
),
addresses: utxoSigningData[i].utxo.address == null
? []
: [utxoSigningData[i].utxo.address!],
addresses:
utxoSigningData[i].utxo.address == null
? []
: [utxoSigningData[i].utxo.address!],
valueStringSats: utxoSigningData[i].utxo.value.toString(),
witness: null,
innerRedeemScriptAsm: null,
@ -741,10 +698,9 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
OutputV2.isarCantDoRequiredInDefaultConstructor(
scriptPubKeyHex: "000000",
valueStringSats: txData.recipients![i].amount.raw.toString(),
addresses: [
txData.recipients![i].address.toString(),
],
walletOwns: (await mainDB.isar.addresses
addresses: [txData.recipients![i].address.toString()],
walletOwns:
(await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
@ -760,22 +716,33 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
// Sign the transaction accordingly
for (var i = 0; i < utxoSigningData.length; i++) {
final value = BigInt.from(utxoSigningData[i].utxo.value);
coinlib.ECPrivateKey key = utxoSigningData[i].keyPair!.privateKey;
final key = utxoSigningData[i].keyPair!.privateKey;
if (clTx.inputs[i] is coinlib.TaprootKeyInput) {
final taproot = coinlib.Taproot(
internalKey: utxoSigningData[i].keyPair!.publicKey,
);
key = taproot.tweakPrivateKey(key);
clTx = clTx.signTaproot(
inputN: i,
key: taproot.tweakPrivateKey(key),
prevOuts: prevOuts,
);
} else if (clTx.inputs[i] is coinlib.LegacyWitnessInput) {
clTx = clTx.signLegacyWitness(inputN: i, key: key, value: value);
} else if (clTx.inputs[i] is coinlib.LegacyInput) {
clTx = clTx.signLegacy(inputN: i, key: key);
} else if (clTx.inputs[i] is coinlib.TaprootSingleScriptSigInput) {
clTx = clTx.signTaprootSingleScriptSig(
inputN: i,
key: key,
prevOuts: prevOuts,
);
} else {
throw Exception(
"Unable to sign input of type ${clTx.inputs[i].runtimeType}",
);
}
clTx = clTx.sign(
inputN: i,
value: value,
key: key,
prevOuts: prevOuts,
);
}
} catch (e, s) {
Logging.instance.e(
@ -839,8 +806,9 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
Future<int> fetchTxCount({required String addressScriptHash}) async {
final transactions =
await electrumXClient.getHistory(scripthash: addressScriptHash);
final transactions = await electrumXClient.getHistory(
scripthash: addressScriptHash,
);
return transactions.length;
}
@ -885,20 +853,21 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
Future<void> updateElectrumX() async {
final failovers = nodeService
.failoverNodesFor(currency: cryptoCurrency)
.map(
(e) => ElectrumXNode(
address: e.host,
port: e.port,
name: e.name,
id: e.id,
useSSL: e.useSSL,
torEnabled: e.torEnabled,
clearnetEnabled: e.clearnetEnabled,
),
)
.toList();
final failovers =
nodeService
.failoverNodesFor(currency: cryptoCurrency)
.map(
(e) => ElectrumXNode(
address: e.host,
port: e.port,
name: e.name,
id: e.id,
useSSL: e.useSSL,
torEnabled: e.torEnabled,
clearnetEnabled: e.clearnetEnabled,
),
)
.toList();
final newNode = await _getCurrentElectrumXNode();
try {
@ -937,9 +906,11 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
int gapCounter = 0;
int highestIndexWithHistory = 0;
for (int index = 0;
gapCounter < cryptoCurrency.maxUnusedAddressGap;
index += txCountBatchSize) {
for (
int index = 0;
gapCounter < cryptoCurrency.maxUnusedAddressGap;
index += txCountBatchSize
) {
Logging.instance.d(
"index: $index, \t GapCounter $chain ${type.name}: $gapCounter",
);
@ -985,9 +956,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
addressArray.add(address);
txCountCallArgs.add(
addressString,
);
txCountCallArgs.add(addressString);
}
// get address tx counts
@ -1115,8 +1084,9 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
for (int i = 0; i < batches.length; i++) {
final response =
await electrumXClient.getBatchHistory(args: batches[i]!);
final response = await electrumXClient.getBatchHistory(
args: batches[i]!,
);
for (int j = 0; j < response.length; j++) {
final entry = response[j];
for (int k = 0; k < entry.length; k++) {
@ -1149,15 +1119,16 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
return allTxHashes;
} catch (e, s) {
Logging.instance
.e("$runtimeType._fetchHistory: ", error: e, stackTrace: s);
Logging.instance.e(
"$runtimeType._fetchHistory: ",
error: e,
stackTrace: s,
);
rethrow;
}
}
Future<UTXO> parseUTXO({
required Map<String, dynamic> jsonUTXO,
}) async {
Future<UTXO> parseUTXO({required Map<String, dynamic> jsonUTXO}) async {
final txn = await electrumXCachedClient.getTransaction(
txHash: jsonUTXO["tx_hash"] as String,
verbose: true,
@ -1179,7 +1150,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
scriptPubKey = output["scriptPubKey"]?["hex"] as String?;
utxoOwnerAddress =
output["scriptPubKey"]?["addresses"]?[0] as String? ??
output["scriptPubKey"]?["address"] as String?;
output["scriptPubKey"]?["address"] as String?;
}
}
@ -1198,7 +1169,8 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
name: checkBlockResult.utxoLabel ?? "",
isBlocked: checkBlockResult.blocked,
blockedReason: checkBlockResult.blockedReason,
isCoinbase: txn["is_coinbase"] as bool? ??
isCoinbase:
txn["is_coinbase"] as bool? ??
txn["is-coinbase"] as bool? ??
txn["iscoinbase"] as bool? ??
isCoinbase,
@ -1216,10 +1188,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
@override
Future<void> updateChainHeight() async {
final height = await fetchChainHeight();
await info.updateCachedChainHeight(
newHeight: height,
isar: mainDB.isar,
);
await info.updateCachedChainHeight(newHeight: height, isar: mainDB.isar);
}
@override
@ -1252,23 +1221,24 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
numberOfBlocksFast: f,
numberOfBlocksAverage: m,
numberOfBlocksSlow: s,
fast: Amount.fromDecimal(
fast,
fractionDigits: info.coin.fractionDigits,
).raw.toInt(),
medium: Amount.fromDecimal(
medium,
fractionDigits: info.coin.fractionDigits,
).raw.toInt(),
slow: Amount.fromDecimal(
slow,
fractionDigits: info.coin.fractionDigits,
).raw.toInt(),
fast:
Amount.fromDecimal(
fast,
fractionDigits: info.coin.fractionDigits,
).raw.toInt(),
medium:
Amount.fromDecimal(
medium,
fractionDigits: info.coin.fractionDigits,
).raw.toInt(),
slow:
Amount.fromDecimal(
slow,
fractionDigits: info.coin.fractionDigits,
).raw.toInt(),
);
Logging.instance.d(
"fetched fees: $feeObject",
);
Logging.instance.d("fetched fees: $feeObject");
_cachedFees = feeObject;
return _cachedFees!;
} catch (e, s) {
@ -1383,9 +1353,10 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
}
} catch (e, s) {
Logging.instance
.e("Exception rethrown from _checkReceivingAddressForTransactions"
"($cryptoCurrency): $e\n$s");
Logging.instance.e(
"Exception rethrown from _checkReceivingAddressForTransactions"
"($cryptoCurrency): $e\n$s",
);
rethrow;
}
}
@ -1434,9 +1405,10 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
await checkChangeAddressForTransactions();
}
} catch (e, s) {
Logging.instance
.e("Exception rethrown from _checkChangeAddressForTransactions"
"($cryptoCurrency): $e\n$s");
Logging.instance.e(
"Exception rethrown from _checkChangeAddressForTransactions"
"($cryptoCurrency): $e\n$s",
);
rethrow;
}
}
@ -1472,47 +1444,25 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
// receiving addresses
Logging.instance.i(
"checking receiving addresses...",
);
Logging.instance.i("checking receiving addresses...");
final canBatch = await serverCanBatch;
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
receiveFutures.add(
canBatch
? checkGapsBatched(
txCountBatchSize,
root,
type,
receiveChain,
)
: checkGapsLinearly(
root,
type,
receiveChain,
),
? checkGapsBatched(txCountBatchSize, root, type, receiveChain)
: checkGapsLinearly(root, type, receiveChain),
);
}
// change addresses
Logging.instance.d(
"checking change addresses...",
);
Logging.instance.d("checking change addresses...");
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
changeFutures.add(
canBatch
? checkGapsBatched(
txCountBatchSize,
root,
type,
changeChain,
)
: checkGapsLinearly(
root,
type,
changeChain,
),
? checkGapsBatched(txCountBatchSize, root, type, changeChain)
: checkGapsLinearly(root, type, changeChain),
);
}
@ -1574,13 +1524,15 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
final notificationAddress =
await (this as PaynymInterface).getMyNotificationAddress();
await (this as BitcoinWallet)
.updateTransactions(overrideAddresses: [notificationAddress]);
await (this as BitcoinWallet).updateTransactions(
overrideAddresses: [notificationAddress],
);
// get own payment code
// isSegwit does not matter here at all
final myCode =
await (this as PaynymInterface).getPaymentCode(isSegwit: false);
final myCode = await (this as PaynymInterface).getPaymentCode(
isSegwit: false,
);
try {
final Set<String> codesToCheck = {};
@ -1648,8 +1600,9 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
for (int i = 0; i < batchArgs.length; i++) {
final response =
await electrumXClient.getBatchUTXOs(args: batchArgs[i]!);
final response = await electrumXClient.getBatchUTXOs(
args: batchArgs[i]!,
);
for (final entry in response) {
if (entry.isNotEmpty) {
fetchedUtxoList.add(entry);
@ -1673,9 +1626,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
for (int i = 0; i < fetchedUtxoList.length; i++) {
for (int j = 0; j < fetchedUtxoList[i].length; j++) {
final utxo = await parseUTXO(
jsonUTXO: fetchedUtxoList[i][j],
);
final utxo = await parseUTXO(jsonUTXO: fetchedUtxoList[i][j]);
outputArray.add(utxo);
}
@ -1695,16 +1646,12 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
@override
Future<TxData> confirmSend({required TxData txData}) async {
try {
Logging.instance.d(
"confirmSend txData: $txData",
);
Logging.instance.d("confirmSend txData: $txData");
final txHash = await electrumXClient.broadcastTransaction(
rawTx: txData.raw!,
);
Logging.instance.d(
"Sent txHash: $txHash",
);
Logging.instance.d("Sent txHash: $txHash");
txData = txData.copyWith(
usedUTXOs:
@ -1742,7 +1689,8 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
final bool coinControl = utxos != null;
final isSendAllCoinControlUtxos = coinControl &&
final isSendAllCoinControlUtxos =
coinControl &&
txData.amount!.raw ==
utxos
.map((e) => e.value)
@ -1811,22 +1759,19 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
final result = await coinSelection(
txData: txData.copyWith(
feeRateAmount: rate,
),
txData: txData.copyWith(feeRateAmount: rate),
isSendAll: isSendAll,
utxos: utxos?.toList(),
coinControl: coinControl,
isSendAllCoinControlUtxos: isSendAllCoinControlUtxos,
);
Logging.instance.d(
"prepare send: $result",
);
Logging.instance.d("prepare send: $result");
if (result.fee!.raw.toInt() < result.vSize!) {
throw Exception(
"Error in fee calculation: Transaction fee (${result.fee!.raw.toInt()}) cannot "
"be less than vSize (${result.vSize})");
"Error in fee calculation: Transaction fee (${result.fee!.raw.toInt()}) cannot "
"be less than vSize (${result.vSize})",
);
}
return result;
@ -1862,16 +1807,15 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
Future<void> _initializeServerVersionAndCheckGenesisHash() async {
try {
final features = await electrumXClient
.getServerFeatures()
.timeout(const Duration(seconds: 5));
Logging.instance.d(
"features: $features",
final features = await electrumXClient.getServerFeatures().timeout(
const Duration(seconds: 5),
);
_serverVersion =
_parseServerVersion(features["server_version"] as String);
Logging.instance.d("features: $features");
_serverVersion = _parseServerVersion(
features["server_version"] as String,
);
if (cryptoCurrency.genesisHash != features['genesis_hash']) {
throw Exception("Genesis hash does not match!");
@ -1896,7 +1840,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
/// Certain coins need to check if the utxo should be marked
/// as blocked as well as give a reason.
Future<({String? blockedReason, bool blocked, String? utxoLabel})>
checkBlockUTXO(
checkBlockUTXO(
Map<String, dynamic> jsonUTXO,
String? scriptPubKeyHex,
Map<String, dynamic> jsonTX,
@ -1948,9 +1892,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
}
} catch (_) {}
Logging.instance.d(
"${info.name} _parseServerVersion($version) => $result",
);
Logging.instance.d("${info.name} _parseServerVersion($version) => $result");
return result;
}
@ -2003,9 +1945,7 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
if (root != null) {
// receiving addresses
Logging.instance.i(
"checking receiving addresses...",
);
Logging.instance.i("checking receiving addresses...");
final canBatch = await serverCanBatch;
@ -2021,24 +1961,18 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
receiveFutures.add(
canBatch
? checkGapsBatched(
txCountBatchSize,
root,
type,
receiveChain,
)
: checkGapsLinearly(
root,
type,
receiveChain,
),
txCountBatchSize,
root,
type,
receiveChain,
)
: checkGapsLinearly(root, type, receiveChain),
);
}
}
// change addresses
Logging.instance.d(
"checking change addresses...",
);
Logging.instance.d("checking change addresses...");
for (final type in cryptoCurrency.supportedDerivationPathTypes) {
final path = cryptoCurrency.constructDerivePath(
derivePathType: type,
@ -2051,16 +1985,12 @@ mixin ElectrumXInterface<T extends ElectrumXCurrencyInterface>
changeFutures.add(
canBatch
? checkGapsBatched(
txCountBatchSize,
root,
type,
changeChain,
)
: checkGapsLinearly(
root,
type,
changeChain,
),
txCountBatchSize,
root,
type,
changeChain,
)
: checkGapsLinearly(root, type, changeChain),
);
}
}

View file

@ -42,34 +42,28 @@ String _notificationDerivationPath({required bool testnet}) =>
String _receivingPaynymAddressDerivationPath(
int index, {
required bool testnet,
}) =>
"${_basePaynymDerivePath(testnet: testnet)}/$index/0";
String _sendPaynymAddressDerivationPath(
int index, {
required bool testnet,
}) =>
}) => "${_basePaynymDerivePath(testnet: testnet)}/$index/0";
String _sendPaynymAddressDerivationPath(int index, {required bool testnet}) =>
"${_basePaynymDerivePath(testnet: testnet)}/0/$index";
mixin PaynymInterface<T extends PaynymCurrencyInterface>
on Bip39HDWallet<T>, ElectrumXInterface<T> {
btc_dart.NetworkType get networkType => btc_dart.NetworkType(
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: btc_dart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
);
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
bech32: cryptoCurrency.networkParams.bech32Hrp,
bip32: btc_dart.Bip32Type(
public: cryptoCurrency.networkParams.pubHDPrefix,
private: cryptoCurrency.networkParams.privHDPrefix,
),
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
wif: cryptoCurrency.networkParams.wifPrefix,
);
Future<bip32.BIP32> getBip47BaseNode() async {
final root = await _getRootNode();
final node = root.derivePath(
_basePaynymDerivePath(
testnet: info.coin.network.isTestNet,
),
_basePaynymDerivePath(testnet: info.coin.network.isTestNet),
);
return node;
}
@ -101,25 +95,29 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}) async {
final keys = await lookupKey(sender.toString());
final address = await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymReceive)
.and()
.group((q) {
if (isSegwit) {
return q
.typeEqualTo(AddressType.p2sh)
.or()
.typeEqualTo(AddressType.p2wpkh);
} else {
return q.typeEqualTo(AddressType.p2pkh);
}
})
.and()
.anyOf<String, Address>(keys, (q, String e) => q.otherDataEqualTo(e))
.sortByDerivationIndexDesc()
.findFirst();
final address =
await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymReceive)
.and()
.group((q) {
if (isSegwit) {
return q
.typeEqualTo(AddressType.p2sh)
.or()
.typeEqualTo(AddressType.p2wpkh);
} else {
return q.typeEqualTo(AddressType.p2pkh);
}
})
.and()
.anyOf<String, Address>(
keys,
(q, String e) => q.otherDataEqualTo(e),
)
.sortByDerivationIndexDesc()
.findFirst();
if (address == null) {
final generatedAddress = await _generatePaynymReceivingAddress(
@ -128,11 +126,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
generateSegwitAddress: isSegwit,
);
final existing = await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(generatedAddress.value)
.findFirst();
final existing =
await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(generatedAddress.value)
.findFirst();
if (existing == null) {
// Add that new address
@ -142,10 +141,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
await mainDB.updateAddress(existing, generatedAddress);
}
return currentReceivingPaynymAddress(
isSegwit: isSegwit,
sender: sender,
);
return currentReceivingPaynymAddress(isSegwit: isSegwit, sender: sender);
} else {
return address;
}
@ -158,9 +154,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}) async {
final root = await _getRootNode();
final node = root.derivePath(
_basePaynymDerivePath(
testnet: info.coin.network.isTestNet,
),
_basePaynymDerivePath(testnet: info.coin.network.isTestNet),
);
final paymentAddress = PaymentAddress(
@ -170,20 +164,22 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
index: 0,
);
final addressString = generateSegwitAddress
? paymentAddress.getReceiveAddressP2WPKH()
: paymentAddress.getReceiveAddressP2PKH();
final addressString =
generateSegwitAddress
? paymentAddress.getReceiveAddressP2WPKH()
: paymentAddress.getReceiveAddressP2PKH();
final address = Address(
walletId: walletId,
value: addressString,
publicKey: [],
derivationIndex: index,
derivationPath: DerivationPath()
..value = _receivingPaynymAddressDerivationPath(
index,
testnet: info.coin.network.isTestNet,
),
derivationPath:
DerivationPath()
..value = _receivingPaynymAddressDerivationPath(
index,
testnet: info.coin.network.isTestNet,
),
type: generateSegwitAddress ? AddressType.p2wpkh : AddressType.p2pkh,
subType: AddressSubType.paynymReceive,
otherData: await storeCode(sender.toString()),
@ -207,20 +203,22 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
index: index,
);
final addressString = generateSegwitAddress
? paymentAddress.getSendAddressP2WPKH()
: paymentAddress.getSendAddressP2PKH();
final addressString =
generateSegwitAddress
? paymentAddress.getSendAddressP2WPKH()
: paymentAddress.getSendAddressP2PKH();
final address = Address(
walletId: walletId,
value: addressString,
publicKey: [],
derivationIndex: index,
derivationPath: DerivationPath()
..value = _sendPaynymAddressDerivationPath(
index,
testnet: info.coin.network.isTestNet,
),
derivationPath:
DerivationPath()
..value = _sendPaynymAddressDerivationPath(
index,
testnet: info.coin.network.isTestNet,
),
type: AddressType.nonWallet,
subType: AddressSubType.paynymSend,
otherData: await storeCode(other.toString()),
@ -251,11 +249,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
generateSegwitAddress: isSegwit,
);
final existing = await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(nextAddress.value)
.findFirst();
final existing =
await mainDB
.getAddresses(walletId)
.filter()
.valueEqualTo(nextAddress.value)
.findFirst();
if (existing == null) {
// Add that new address
@ -312,26 +311,18 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
Future<bip32.BIP32> deriveNotificationBip32Node() async {
final root = await _getRootNode();
final node = root
.derivePath(
_basePaynymDerivePath(
testnet: info.coin.network.isTestNet,
),
)
.derivePath(_basePaynymDerivePath(testnet: info.coin.network.isTestNet))
.derive(0);
return node;
}
/// fetch or generate this wallet's bip47 payment code
Future<PaymentCode> getPaymentCode({
required bool isSegwit,
}) async {
Future<PaymentCode> getPaymentCode({required bool isSegwit}) async {
final node = await _getRootNode();
final paymentCode = PaymentCode.fromBip32Node(
node.derivePath(
_basePaynymDerivePath(
testnet: info.coin.network.isTestNet,
),
_basePaynymDerivePath(testnet: info.coin.network.isTestNet),
),
networkType: networkType,
shouldSetSegwitBit: isSegwit,
@ -351,8 +342,9 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
Future<String> signStringWithNotificationKey(String data) async {
final bytes =
await signWithNotificationKey(Uint8List.fromList(utf8.encode(data)));
final bytes = await signWithNotificationKey(
Uint8List.fromList(utf8.encode(data)),
);
return Format.uint8listToString(bytes);
}
@ -411,15 +403,19 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
for (int i = startIndex; i < maxCount; i++) {
final keys = await lookupKey(pCode.toString());
final address = await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymSend)
.and()
.anyOf<String, Address>(keys, (q, String e) => q.otherDataEqualTo(e))
.and()
.derivationIndexEqualTo(i)
.findFirst();
final address =
await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymSend)
.and()
.anyOf<String, Address>(
keys,
(q, String e) => q.otherDataEqualTo(e),
)
.and()
.derivationIndexEqualTo(i)
.findFirst();
if (address != null) {
final count = await fetchTxCount(
@ -506,21 +502,26 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
int outputsBeingUsed = 0;
final List<UTXO> utxoObjectsToUse = [];
for (int i = 0;
satoshisBeingUsed < amountToSend.raw && i < spendableOutputs.length;
i++) {
for (
int i = 0;
satoshisBeingUsed < amountToSend.raw && i < spendableOutputs.length;
i++
) {
utxoObjectsToUse.add(spendableOutputs[i]);
satoshisBeingUsed += BigInt.from(spendableOutputs[i].value);
outputsBeingUsed += 1;
}
// add additional outputs if required
for (int i = 0;
i < additionalOutputs && outputsBeingUsed < spendableOutputs.length;
i++) {
for (
int i = 0;
i < additionalOutputs && outputsBeingUsed < spendableOutputs.length;
i++
) {
utxoObjectsToUse.add(spendableOutputs[outputsBeingUsed]);
satoshisBeingUsed +=
BigInt.from(spendableOutputs[outputsBeingUsed].value);
satoshisBeingUsed += BigInt.from(
spendableOutputs[outputsBeingUsed].value,
);
outputsBeingUsed += 1;
}
@ -534,8 +535,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
change: BigInt.zero,
// override amount to get around absurd fees error
overrideAmountForTesting: satoshisBeingUsed,
))
.item2,
)).item2,
);
final vSizeForWithChange = BigInt.from(
@ -543,8 +543,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
targetPaymentCodeString: targetPaymentCodeString,
utxoSigningData: utxoSigningData,
change: satoshisBeingUsed - amountToSend.raw,
))
.item2,
)).item2,
);
// Assume 2 outputs, for recipient and payment code script
@ -836,10 +835,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
clTx = clTx.addOutput(output);
clTx = clTx.addOutput(
coinlib.Output.fromScriptBytes(
BigInt.zero,
opReturnScript,
),
coinlib.Output.fromScriptBytes(BigInt.zero, opReturnScript),
);
// TODO: add possible change output and mark output as dangerous
@ -859,32 +855,64 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
clTx = clTx.addOutput(output);
}
clTx = clTx.sign(
inputN: 0,
value: BigInt.from(utxo.value),
key: myKeyPair.privateKey,
prevOuts: prevOuts,
);
if (clTx.inputs[0] is coinlib.TaprootKeyInput) {
final taproot = coinlib.Taproot(internalKey: myKeyPair.publicKey);
clTx = clTx.signTaproot(
inputN: 0,
key: taproot.tweakPrivateKey(myKeyPair.privateKey),
prevOuts: prevOuts,
);
} else if (clTx.inputs[0] is coinlib.LegacyWitnessInput) {
clTx = clTx.signLegacyWitness(
inputN: 0,
key: myKeyPair.privateKey,
value: BigInt.from(utxo.value),
);
} else if (clTx.inputs[0] is coinlib.LegacyInput) {
clTx = clTx.signLegacy(inputN: 0, key: myKeyPair.privateKey);
} else if (clTx.inputs[0] is coinlib.TaprootSingleScriptSigInput) {
clTx = clTx.signTaprootSingleScriptSig(
inputN: 0,
key: myKeyPair.privateKey,
prevOuts: prevOuts,
);
} else {
throw Exception(
"Unable to sign input of type ${clTx.inputs[0].runtimeType}",
);
}
// sign rest of possible inputs
for (int i = 1; i < utxoSigningData.length; i++) {
final value = BigInt.from(utxoSigningData[i].utxo.value);
coinlib.ECPrivateKey key = utxoSigningData[i].keyPair!.privateKey;
final key = utxoSigningData[i].keyPair!.privateKey;
if (clTx.inputs[i] is coinlib.TaprootKeyInput) {
final taproot = coinlib.Taproot(
internalKey: utxoSigningData[i].keyPair!.publicKey,
);
key = taproot.tweakPrivateKey(key);
clTx = clTx.signTaproot(
inputN: i,
key: taproot.tweakPrivateKey(key),
prevOuts: prevOuts,
);
} else if (clTx.inputs[i] is coinlib.LegacyWitnessInput) {
clTx = clTx.signLegacyWitness(inputN: i, key: key, value: value);
} else if (clTx.inputs[i] is coinlib.LegacyInput) {
clTx = clTx.signLegacy(inputN: i, key: key);
} else if (clTx.inputs[i] is coinlib.TaprootSingleScriptSigInput) {
clTx = clTx.signTaprootSingleScriptSig(
inputN: i,
key: key,
prevOuts: prevOuts,
);
} else {
throw Exception(
"Unable to sign input of type ${clTx.inputs[i].runtimeType}",
);
}
clTx = clTx.sign(
inputN: i,
value: value,
key: key,
prevOuts: prevOuts,
);
}
return Tuple2(clTx.toHex(), clTx.vSize());
@ -894,13 +922,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
}
Future<TxData> broadcastNotificationTx({
required TxData txData,
}) async {
Future<TxData> broadcastNotificationTx({required TxData txData}) async {
try {
Logging.instance.d("confirmNotificationTx txData: $txData");
final txHash =
await electrumXClient.broadcastTransaction(rawTx: txData.raw!);
final txHash = await electrumXClient.broadcastTransaction(
rawTx: txData.raw!,
);
Logging.instance.d("Sent txHash: $txHash");
try {
@ -913,10 +940,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
);
}
return txData.copyWith(
txid: txHash,
txHash: txHash,
);
return txData.copyWith(txid: txHash, txHash: txHash);
} catch (e, s) {
Logging.instance.e(
"Exception rethrown from confirmSend(): ",
@ -964,12 +988,13 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
final myNotificationAddress = await getMyNotificationAddress();
final txns = await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.findAll();
final txns =
await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.findAll();
for (final tx in txns) {
switch (tx.type) {
@ -978,9 +1003,7 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
for (final outputAddress in output.addresses) {
if (outputAddress == myNotificationAddress.value) {
final unBlindedPaymentCode =
await unBlindedPaymentCodeFromTransaction(
transaction: tx,
);
await unBlindedPaymentCodeFromTransaction(transaction: tx);
if (unBlindedPaymentCode != null &&
paymentCodeString == unBlindedPaymentCode.toString()) {
@ -990,8 +1013,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
final unBlindedPaymentCodeBad =
await unBlindedPaymentCodeFromTransactionBad(
transaction: tx,
);
transaction: tx,
);
if (unBlindedPaymentCodeBad != null &&
paymentCodeString == unBlindedPaymentCodeBad.toString()) {
@ -1005,14 +1028,15 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
case TransactionType.outgoing:
for (final output in tx.outputs) {
for (final outputAddress in output.addresses) {
final address = await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.valueEqualTo(outputAddress)
.findFirst();
final address =
await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.valueEqualTo(outputAddress)
.findFirst();
if (address?.otherData != null) {
final code = await paymentCodeStringByKey(address!.otherData!);
@ -1055,8 +1079,9 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
required TransactionV2 transaction,
}) async {
try {
final blindedCodeBytes =
Bip47Utils.getBlindedPaymentCodeBytesFrom(transaction);
final blindedCodeBytes = Bip47Utils.getBlindedPaymentCodeBytesFrom(
transaction,
);
// transaction does not contain a payment code
if (blindedCodeBytes == null) {
@ -1113,8 +1138,9 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
required TransactionV2 transaction,
}) async {
try {
final blindedCodeBytes =
Bip47Utils.getBlindedPaymentCodeBytesFrom(transaction);
final blindedCodeBytes = Bip47Utils.getBlindedPaymentCodeBytesFrom(
transaction,
);
// transaction does not contain a payment code
if (blindedCodeBytes == null) {
@ -1168,13 +1194,14 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
Future<List<PaymentCode>>
getAllPaymentCodesFromNotificationTransactions() async {
final txns = await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.findAll();
getAllPaymentCodesFromNotificationTransactions() async {
final txns =
await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.findAll();
final List<PaymentCode> codes = [];
@ -1182,20 +1209,23 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
// tx is sent so we can check the address's otherData for the code String
if (tx.type == TransactionType.outgoing) {
for (final output in tx.outputs) {
for (final outputAddress
in output.addresses.where((e) => e.isNotEmpty)) {
final address = await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.valueEqualTo(outputAddress)
.findFirst();
for (final outputAddress in output.addresses.where(
(e) => e.isNotEmpty,
)) {
final address =
await mainDB.isar.addresses
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.valueEqualTo(outputAddress)
.findFirst();
if (address?.otherData != null) {
final codeString =
await paymentCodeStringByKey(address!.otherData!);
final codeString = await paymentCodeStringByKey(
address!.otherData!,
);
if (codeString != null &&
codes.where((e) => e.toString() == codeString).isEmpty) {
codes.add(
@ -1236,14 +1266,15 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
Future<void> checkForNotificationTransactionsTo(
Set<String> otherCodeStrings,
) async {
final sentNotificationTransactions = await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.and()
.typeEqualTo(TransactionType.outgoing)
.findAll();
final sentNotificationTransactions =
await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.subTypeEqualTo(TransactionSubType.bip47Notification)
.and()
.typeEqualTo(TransactionType.outgoing)
.findAll();
final List<PaymentCode> codes = [];
for (final codeString in otherCodeStrings) {
@ -1260,8 +1291,10 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
final notificationAddress = code.notificationAddressP2PKH();
if (outputAddress == notificationAddress) {
Address? storedAddress =
await mainDB.getAddress(walletId, outputAddress);
Address? storedAddress = await mainDB.getAddress(
walletId,
outputAddress,
);
if (storedAddress == null) {
// most likely not mine
storedAddress = Address(
@ -1343,10 +1376,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
int outgoingGapCounter = 0;
// non segwit receiving
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
receivingGapCounter < maxUnusedAddressGap;
i++) {
for (
int i = 0;
i < maxNumberOfIndexesToCheck &&
receivingGapCounter < maxUnusedAddressGap;
i++
) {
if (receivingGapCounter < maxUnusedAddressGap) {
final address = await _generatePaynymReceivingAddress(
sender: other,
@ -1371,10 +1406,11 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
// non segwit sends
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
outgoingGapCounter < maxUnusedAddressGap;
i++) {
for (
int i = 0;
i < maxNumberOfIndexesToCheck && outgoingGapCounter < maxUnusedAddressGap;
i++
) {
if (outgoingGapCounter < maxUnusedAddressGap) {
final address = await _generatePaynymSendAddress(
other: other,
@ -1403,10 +1439,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
int receivingGapCounterSegwit = 0;
int outgoingGapCounterSegwit = 0;
// segwit receiving
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
receivingGapCounterSegwit < maxUnusedAddressGap;
i++) {
for (
int i = 0;
i < maxNumberOfIndexesToCheck &&
receivingGapCounterSegwit < maxUnusedAddressGap;
i++
) {
if (receivingGapCounterSegwit < maxUnusedAddressGap) {
final address = await _generatePaynymReceivingAddress(
sender: other,
@ -1431,10 +1469,12 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
// segwit sends
for (int i = 0;
i < maxNumberOfIndexesToCheck &&
outgoingGapCounterSegwit < maxUnusedAddressGap;
i++) {
for (
int i = 0;
i < maxNumberOfIndexesToCheck &&
outgoingGapCounterSegwit < maxUnusedAddressGap;
i++
) {
if (outgoingGapCounterSegwit < maxUnusedAddressGap) {
final address = await _generatePaynymSendAddress(
other: other,
@ -1463,25 +1503,24 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
Future<Address> getMyNotificationAddress() async {
final storedAddress = await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.typeEqualTo(AddressType.p2pkh)
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.findFirst();
final storedAddress =
await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.typeEqualTo(AddressType.p2pkh)
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.findFirst();
if (storedAddress != null) {
return storedAddress;
} else {
final root = await _getRootNode();
final node = root.derivePath(
_basePaynymDerivePath(
testnet: info.coin.network.isTestNet,
),
_basePaynymDerivePath(testnet: info.coin.network.isTestNet),
);
final paymentCode = PaymentCode.fromBip32Node(
node,
@ -1493,23 +1532,19 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
pubkey: paymentCode.notificationPublicKey(),
);
final addressString = btc_dart
.P2PKH(
data: data,
network: networkType,
)
.data
.address!;
final addressString =
btc_dart.P2PKH(data: data, network: networkType).data.address!;
Address address = Address(
walletId: walletId,
value: addressString,
publicKey: paymentCode.getPubKey(),
derivationIndex: 0,
derivationPath: DerivationPath()
..value = _notificationDerivationPath(
testnet: info.coin.network.isTestNet,
),
derivationPath:
DerivationPath()
..value = _notificationDerivationPath(
testnet: info.coin.network.isTestNet,
),
type: AddressType.p2pkh,
subType: AddressSubType.paynymNotification,
otherData: await storeCode(paymentCode.toString()),
@ -1520,16 +1555,17 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
// beginning to see if there already was notification address. This would
// lead to a Unique Index violation error
await mainDB.isar.writeTxn(() async {
final storedAddress = await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.typeEqualTo(AddressType.p2pkh)
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.findFirst();
final storedAddress =
await mainDB
.getAddresses(walletId)
.filter()
.subTypeEqualTo(AddressSubType.paynymNotification)
.and()
.typeEqualTo(AddressType.p2pkh)
.and()
.not()
.typeEqualTo(AddressType.nonWallet)
.findFirst();
if (storedAddress == null) {
await mainDB.isar.addresses.put(address);
@ -1607,45 +1643,43 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
overrideAddresses ?? await fetchAddressesForElectrumXScan();
// Separate receiving and change addresses.
final Set<String> receivingAddresses = allAddressesOld
.where(
(e) =>
e.subType == AddressSubType.receiving ||
e.subType == AddressSubType.paynymNotification ||
e.subType == AddressSubType.paynymReceive,
)
.map((e) => e.value)
.toSet();
final Set<String> changeAddresses = allAddressesOld
.where((e) => e.subType == AddressSubType.change)
.map((e) => e.value)
.toSet();
final Set<String> receivingAddresses =
allAddressesOld
.where(
(e) =>
e.subType == AddressSubType.receiving ||
e.subType == AddressSubType.paynymNotification ||
e.subType == AddressSubType.paynymReceive,
)
.map((e) => e.value)
.toSet();
final Set<String> changeAddresses =
allAddressesOld
.where((e) => e.subType == AddressSubType.change)
.map((e) => e.value)
.toSet();
// Remove duplicates.
final allAddressesSet = {...receivingAddresses, ...changeAddresses};
// Fetch history from ElectrumX.
final List<Map<String, dynamic>> allTxHashes =
await fetchHistory(allAddressesSet);
final unconfirmedTxs = await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.heightIsNull()
.or()
.heightEqualTo(0)
.txidProperty()
.findAll();
allTxHashes.addAll(
unconfirmedTxs.map(
(e) => {
"tx_hash": e,
},
),
final List<Map<String, dynamic>> allTxHashes = await fetchHistory(
allAddressesSet,
);
final unconfirmedTxs =
await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.heightIsNull()
.or()
.heightEqualTo(0)
.txidProperty()
.findAll();
allTxHashes.addAll(unconfirmedTxs.map((e) => {"tx_hash": e}));
// Only parse new txs (not in db yet).
final List<Map<String, dynamic>> allTransactions = [];
for (final txHash in allTxHashes) {
@ -1670,16 +1704,17 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
} catch (e) {
// tx no longer exists then delete from local db
if (e.toString().contains(
"JSON-RPC error 2: daemon error: DaemonError({'code': -5, "
"'message': 'No such mempool or blockchain transaction",
)) {
"JSON-RPC error 2: daemon error: DaemonError({'code': -5, "
"'message': 'No such mempool or blockchain transaction",
)) {
await mainDB.isar.writeTxn(
() async => await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.txidEqualTo(txid)
.deleteFirst(),
() async =>
await mainDB.isar.transactionV2s
.where()
.walletIdEqualTo(walletId)
.filter()
.txidEqualTo(txid)
.deleteFirst(),
);
continue;
} else {
@ -1802,8 +1837,9 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
TransactionSubType subType = TransactionSubType.none;
if (outputs.length > 1 && inputs.isNotEmpty) {
for (int i = 0; i < outputs.length; i++) {
final List<String>? scriptChunks =
outputs[i].scriptPubKeyAsm?.split(" ");
final List<String>? scriptChunks = outputs[i].scriptPubKeyAsm?.split(
" ",
);
if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") {
final blindedPaymentCode = scriptChunks![1];
final bytes = blindedPaymentCode.toUint8ListFromHex;
@ -1856,7 +1892,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
txid: txData["txid"] as String,
height: txData["height"] as int?,
version: txData["version"] as int,
timestamp: txData["blocktime"] as int? ??
timestamp:
txData["blocktime"] as int? ??
DateTime.timestamp().millisecondsSinceEpoch ~/ 1000,
inputs: List.unmodifiable(inputs),
outputs: List.unmodifiable(outputs),
@ -1872,12 +1909,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
}
@override
Future<
({
String? blockedReason,
bool blocked,
String? utxoLabel,
})> checkBlockUTXO(
Future<({String? blockedReason, bool blocked, String? utxoLabel})>
checkBlockUTXO(
Map<String, dynamic> jsonUTXO,
String? scriptPubKeyHex,
Map<String, dynamic>? jsonTX,
@ -1905,7 +1938,8 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
blocked = true;
blockedReason = "Incoming paynym notification transaction.";
} else {
blockedReason = "Paynym notification change output. Incautious "
blockedReason =
"Paynym notification change output. Incautious "
"handling of change outputs from notification transactions "
"may cause unintended loss of privacy.";
utxoLabel = blockedReason;
@ -1920,23 +1954,21 @@ mixin PaynymInterface<T extends PaynymCurrencyInterface>
return (
blockedReason: blockedReason,
blocked: blocked,
utxoLabel: utxoLabel
utxoLabel: utxoLabel,
);
}
@override
FilterOperation? get transactionFilterOperation => FilterGroup.not(
const FilterGroup.and(
[
FilterCondition.equalTo(
property: r"subType",
value: TransactionSubType.bip47Notification,
),
FilterCondition.equalTo(
property: r"type",
value: TransactionType.incoming,
),
],
),
);
const FilterGroup.and([
FilterCondition.equalTo(
property: r"subType",
value: TransactionSubType.bip47Notification,
),
FilterCondition.equalTo(
property: r"type",
value: TransactionType.incoming,
),
]),
);
}

View file

@ -352,21 +352,19 @@ packages:
coinlib:
dependency: "direct overridden"
description:
path: coinlib
ref: "0acacfd17eacf72135c693a7b862bd9b7cc56739"
resolved-ref: "0acacfd17eacf72135c693a7b862bd9b7cc56739"
url: "https://github.com/julian-CStack/coinlib.git"
source: git
version: "2.2.0"
name: coinlib
sha256: f99c090ca300b6c9b5414dc100f7f36f49a5a2af31d477b3ce04a605c5f1103c
url: "https://pub.dev"
source: hosted
version: "3.1.0"
coinlib_flutter:
dependency: "direct main"
description:
path: coinlib_flutter
ref: "0acacfd17eacf72135c693a7b862bd9b7cc56739"
resolved-ref: "0acacfd17eacf72135c693a7b862bd9b7cc56739"
url: "https://github.com/julian-CStack/coinlib.git"
source: git
version: "2.2.0"
name: coinlib_flutter
sha256: "185c622986d12d2ccda98f151ce047360464dd7a6cbb6877781a9816d14bb8c4"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
collection:
dependency: transitive
description:
@ -832,8 +830,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: ca0c72cecc40fc0bfbafc0d26af675d973ab516b
resolved-ref: ca0c72cecc40fc0bfbafc0d26af675d973ab516b
ref: "33e1034911b842c57bdf6ddaa825cbf635a0c9db"
resolved-ref: "33e1034911b842c57bdf6ddaa825cbf635a0c9db"
url: "https://github.com/cypherstack/flutter_libsparkmobile.git"
source: git
version: "0.0.2"
@ -1247,7 +1245,7 @@ packages:
path: "crypto_plugins/flutter_liblelantus"
relative: true
source: path
version: "0.0.2"
version: "0.0.3"
lints:
dependency: transitive
description:

View file

@ -2,19 +2,13 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
mkdir -p build
. ./config.sh
./install_ndk.sh
PLUGINS_DIR=../../crypto_plugins
(cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh )
set_rust_to_1720
(cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh )
wait

View file

@ -2,19 +2,13 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
mkdir -p build
. ./config.sh
./install_ndk.sh
PLUGINS_DIR=../../crypto_plugins
(cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh )
set_rust_to_1720
(cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh )
wait

View file

@ -4,19 +4,13 @@ set -x -e
# todo: revisit following at some point
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
mkdir -p build
. ./config.sh
./install_ndk.sh
PLUGINS_DIR=../../crypto_plugins
(cd "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android && ./build_all.sh )
(cd "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android && ./build_all.sh )
set_rust_to_1720
(cd "${PLUGINS_DIR}"/frostdart/scripts/android && ./build_all.sh )
wait

View file

@ -1,7 +1,5 @@
#!/bin/sh
export WORKDIR="$(pwd)/"build
export ANDROID_NDK_ZIP=${WORKDIR}/android-ndk-r20b.zip
export TOOLCHAIN_DIR="${WORKDIR}/toolchain"
# Change this Value to a lower number if you run out of memory while compiling
export OVERRIDE_THREADS="$(nproc)"

View file

@ -1,21 +0,0 @@
#!/bin/sh
mkdir -p build
. ./config.sh
ANDROID_NDK_SHA256="8381c440fe61fcbb01e209211ac01b519cd6adf51ab1c2281d5daad6ca4c8c8c"
if [ ! -e "$ANDROID_NDK_ZIP" ]; then
curl https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip -o "${ANDROID_NDK_ZIP}"
fi
echo "${ANDROID_NDK_SHA256}" "${ANDROID_NDK_ZIP}" | sha256sum -c || exit 1
PLUGINS_DIR=../../crypto_plugins
mkdir -p "${PLUGINS_DIR}"/flutter_libmonero/scripts/android/build
mkdir -p "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android/build
mkdir -p "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android/build
cp "${ANDROID_NDK_ZIP}" "${PLUGINS_DIR}"/flutter_libmonero/scripts/android/build/
cp "${ANDROID_NDK_ZIP}" "${PLUGINS_DIR}"/flutter_liblelantus/scripts/android/build/
cp "${ANDROID_NDK_ZIP}" "${PLUGINS_DIR}"/flutter_libepiccash/scripts/android/build/

View file

@ -15,7 +15,7 @@ android {
namespace "com.place.holder"
compileSdk flutter.compileSdkVersion
// ndkVersion flutter.ndkVersion
ndkVersion = "26.1.10909125"
ndkVersion = "28.0.13004108"
packagingOptions {
pickFirst 'lib/x86/libc++_shared.so'
@ -90,6 +90,7 @@ android {
task.doFirst {
println "The compileSdkVersion is $flutter.compileSdkVersion"
println "The targetSdkVersion is $flutter.targetSdkVersion"
println "The ndkVersion is $ndkVersion"
}
}
}

View file

@ -1,6 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.place.holder">
<!-- Flutter needs it to communicate with the running application
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>

View file

@ -1,10 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.place.holder">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission
android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission

View file

@ -1,6 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.place.holder">
<!-- Flutter needs it to communicate with the running application
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>

View file

@ -38,7 +38,7 @@ dependencies:
flutter_libsparkmobile:
git:
url: https://github.com/cypherstack/flutter_libsparkmobile.git
ref: ca0c72cecc40fc0bfbafc0d26af675d973ab516b
ref: 33e1034911b842c57bdf6ddaa825cbf635a0c9db
# cs_monero compat (unpublished)
compat:
@ -176,12 +176,7 @@ dependencies:
convert: ^3.1.1
flutter_hooks: ^0.20.3
meta: ^1.9.1
# coinlib_flutter: ^2.1.0-rc.1
coinlib_flutter:
git:
url: https://github.com/julian-CStack/coinlib.git
ref: 0acacfd17eacf72135c693a7b862bd9b7cc56739
path: coinlib_flutter
coinlib_flutter: ^3.0.0
electrum_adapter:
git:
url: https://github.com/cypherstack/electrum_adapter.git
@ -261,18 +256,9 @@ dependency_overrides:
# needed for dart 3.5+ (at least for now)
win32: ^5.5.4
# coin lib git for testing while waiting for publishing
coinlib:
git:
url: https://github.com/julian-CStack/coinlib.git
ref: 0acacfd17eacf72135c693a7b862bd9b7cc56739
path: coinlib
coinlib_flutter:
git:
url: https://github.com/julian-CStack/coinlib.git
ref: 0acacfd17eacf72135c693a7b862bd9b7cc56739
path: coinlib_flutter
# namecoin names lib needs to be updated
coinlib: ^3.0.0
coinlib_flutter: ^3.0.0
bip47:
git:

View file

@ -2,10 +2,6 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
# ensure ios rust triples are there
rustup target add aarch64-apple-ios
rustup target add x86_64-apple-ios
@ -16,7 +12,6 @@ rustup target add x86_64-apple-ios
(cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh )
wait

View file

@ -2,10 +2,6 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
# ensure ios rust triples are there
rustup target add aarch64-apple-ios
rustup target add x86_64-apple-ios
@ -16,7 +12,6 @@ rustup target add x86_64-apple-ios
(cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh )
wait

View file

@ -4,10 +4,6 @@ set -x -e
# todo: revisit following at some point
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
# ensure ios rust triples are there
rustup target add aarch64-apple-ios
rustup target add x86_64-apple-ios
@ -18,7 +14,6 @@ rustup target add x86_64-apple-ios
(cd ../../crypto_plugins/flutter_liblelantus/scripts/ios && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/ios && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/ios && ./build_all.sh )
wait

View file

@ -2,10 +2,6 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
# for arm
# flutter-elinux clean
# flutter-elinux pub get
@ -14,7 +10,6 @@ mkdir -p build
./build_secure_storage_deps.sh
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh )
./build_secp256k1.sh

View file

@ -2,10 +2,6 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
# for arm
# flutter-elinux clean
# flutter-elinux pub get
@ -14,7 +10,6 @@ mkdir -p build
./build_secure_storage_deps.sh
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh )
./build_secp256k1.sh

View file

@ -4,9 +4,6 @@ set -x -e
# todo: revisit following at some point
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
# for arm
# flutter-elinux clean
@ -16,7 +13,6 @@ mkdir -p build
./build_secure_storage_deps.sh &
(cd ../../crypto_plugins/flutter_liblelantus/scripts/linux && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/linux && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/linux && ./build_all.sh )
./build_secp256k1.sh

View file

@ -2,17 +2,10 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
(cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh )
wait
echo "Done building"
# set rust (back) to a more recent stable release to allow stack wallet to build tor
set_rust_to_1720

View file

@ -2,17 +2,9 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
(cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh )
wait
echo "Done building"
# set rust (back) to a more recent stable release to allow stack wallet to build tor
set_rust_to_1720

View file

@ -4,17 +4,10 @@ set -x -e
# todo: revisit following at some point
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
(cd ../../crypto_plugins/flutter_liblelantus/scripts/macos && ./build_all.sh )
(cd ../../crypto_plugins/flutter_libepiccash/scripts/macos && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/macos && ./build_all.sh )
wait
echo "Done building"
# set rust (back) to a more recent stable release to allow stack wallet to build tor
set_rust_to_1720

View file

@ -1,19 +0,0 @@
#!/bin/sh
set_rust_to_1671() {
if rustup toolchain list | grep -q "1.67.1"; then
rustup default 1.67.1
else
echo "Rust version 1.67.1 is not installed. Please install it using 'rustup install 1.67.1'." >&2
exit 1
fi
}
set_rust_to_1720() {
if rustup toolchain list | grep -q "1.72.0"; then
rustup default 1.72.0
else
echo "Rust version 1.72.0 is not installed. Please install it using 'rustup install 1.72.0'." >&2
exit 1
fi
}

View file

@ -2,14 +2,9 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
mkdir -p build
(cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh )
./build_secp256k1_wsl.sh

View file

@ -2,14 +2,9 @@
set -x -e
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
mkdir -p build
(cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh )
./build_secp256k1_wsl.sh

View file

@ -4,14 +4,9 @@ set -x -e
# todo: revisit following at some point
# libepiccash requires old rust
source ../rust_version.sh
set_rust_to_1671
mkdir -p build
(cd ../../crypto_plugins/flutter_libepiccash/scripts/windows && ./build_all.sh )
(cd ../../crypto_plugins/flutter_liblelantus/scripts/windows && ./build_all.sh )
set_rust_to_1720
(cd ../../crypto_plugins/frostdart/scripts/windows && ./build_all.sh )
./build_secp256k1_wsl.sh