mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-10 12:44:31 +00:00
handle send all spark properly
This commit is contained in:
parent
1e1a472d42
commit
b441157398
5 changed files with 120 additions and 29 deletions
|
@ -141,7 +141,11 @@ class CachedElectrumXClient {
|
||||||
set["blockHash"] = newSet["blockHash"];
|
set["blockHash"] = newSet["blockHash"];
|
||||||
for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) {
|
for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) {
|
||||||
// TODO verify this is correct (or append?)
|
// TODO verify this is correct (or append?)
|
||||||
set["coins"].insert(0, newSet["coins"][i]);
|
if ((set["coins"] as List)
|
||||||
|
.where((e) => e[0] == newSet["coins"][i][0])
|
||||||
|
.isEmpty) {
|
||||||
|
set["coins"].insert(0, newSet["coins"][i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// save set to db
|
// save set to db
|
||||||
await box.put(groupId, set);
|
await box.put(groupId, set);
|
||||||
|
|
|
@ -535,7 +535,6 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
address: _address!,
|
address: _address!,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
memo: memoController.text,
|
memo: memoController.text,
|
||||||
subtractFeeFromAmount: false,
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
: null,
|
: null,
|
||||||
|
@ -570,7 +569,6 @@ class _SendViewState extends ConsumerState<SendView> {
|
||||||
address: _address!,
|
address: _address!,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
memo: memoController.text,
|
memo: memoController.text,
|
||||||
subtractFeeFromAmount: false,
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
: null,
|
: null,
|
||||||
|
|
|
@ -332,7 +332,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
address: _address!,
|
address: _address!,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
memo: memoController.text,
|
memo: memoController.text,
|
||||||
subtractFeeFromAmount: false,
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
: null,
|
: null,
|
||||||
|
@ -367,7 +366,6 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
||||||
address: _address!,
|
address: _address!,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
memo: memoController.text,
|
memo: memoController.text,
|
||||||
subtractFeeFromAmount: false,
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
: null,
|
: null,
|
||||||
|
|
|
@ -60,7 +60,6 @@ class TxData {
|
||||||
({
|
({
|
||||||
String address,
|
String address,
|
||||||
Amount amount,
|
Amount amount,
|
||||||
bool subtractFeeFromAmount,
|
|
||||||
String memo,
|
String memo,
|
||||||
})>? sparkRecipients;
|
})>? sparkRecipients;
|
||||||
|
|
||||||
|
@ -148,7 +147,6 @@ class TxData {
|
||||||
({
|
({
|
||||||
String address,
|
String address,
|
||||||
Amount amount,
|
Amount amount,
|
||||||
bool subtractFeeFromAmount,
|
|
||||||
String memo,
|
String memo,
|
||||||
})>?
|
})>?
|
||||||
sparkRecipients,
|
sparkRecipients,
|
||||||
|
|
|
@ -125,8 +125,32 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
.isUsedEqualTo(false)
|
.isUsedEqualTo(false)
|
||||||
.and()
|
.and()
|
||||||
.heightIsNotNull()
|
.heightIsNotNull()
|
||||||
|
.and()
|
||||||
|
.not()
|
||||||
|
.valueIntStringEqualTo("0")
|
||||||
.findAll();
|
.findAll();
|
||||||
|
|
||||||
|
final available = info.cachedBalanceTertiary.spendable;
|
||||||
|
|
||||||
|
final txAmount = (txData.recipients ?? []).map((e) => e.amount).fold(
|
||||||
|
Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
),
|
||||||
|
(p, e) => p + e) +
|
||||||
|
(txData.sparkRecipients ?? []).map((e) => e.amount).fold(
|
||||||
|
Amount(
|
||||||
|
rawValue: BigInt.zero,
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
),
|
||||||
|
(p, e) => p + e);
|
||||||
|
|
||||||
|
if (txAmount > available) {
|
||||||
|
throw Exception("Insufficient Spark balance");
|
||||||
|
}
|
||||||
|
|
||||||
|
final bool isSendAll = available == txAmount;
|
||||||
|
|
||||||
// prepare coin data for ffi
|
// prepare coin data for ffi
|
||||||
final serializedCoins = coins
|
final serializedCoins = coins
|
||||||
.map((e) => (
|
.map((e) => (
|
||||||
|
@ -177,34 +201,89 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
}
|
}
|
||||||
final privateKey = root.derivePath(derivationPath).privateKey.data;
|
final privateKey = root.derivePath(derivationPath).privateKey.data;
|
||||||
|
|
||||||
final txb = btc.TransactionBuilder(
|
final btcDartNetwork = btc.NetworkType(
|
||||||
network: btc.NetworkType(
|
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
|
||||||
messagePrefix: cryptoCurrency.networkParams.messagePrefix,
|
bech32: cryptoCurrency.networkParams.bech32Hrp,
|
||||||
bech32: cryptoCurrency.networkParams.bech32Hrp,
|
bip32: btc.Bip32Type(
|
||||||
bip32: btc.Bip32Type(
|
public: cryptoCurrency.networkParams.pubHDPrefix,
|
||||||
public: cryptoCurrency.networkParams.pubHDPrefix,
|
private: cryptoCurrency.networkParams.privHDPrefix,
|
||||||
private: cryptoCurrency.networkParams.privHDPrefix,
|
|
||||||
),
|
|
||||||
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
|
|
||||||
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
|
|
||||||
wif: cryptoCurrency.networkParams.wifPrefix,
|
|
||||||
),
|
),
|
||||||
|
pubKeyHash: cryptoCurrency.networkParams.p2pkhPrefix,
|
||||||
|
scriptHash: cryptoCurrency.networkParams.p2shPrefix,
|
||||||
|
wif: cryptoCurrency.networkParams.wifPrefix,
|
||||||
|
);
|
||||||
|
final txb = btc.TransactionBuilder(
|
||||||
|
network: btcDartNetwork,
|
||||||
);
|
);
|
||||||
txb.setLockTime(await chainHeight);
|
txb.setLockTime(await chainHeight);
|
||||||
txb.setVersion(3 | (9 << 16));
|
txb.setVersion(3 | (9 << 16));
|
||||||
|
|
||||||
|
final List<({String address, Amount amount})> recipientsWithFeeSubtracted =
|
||||||
|
[];
|
||||||
|
final List<
|
||||||
|
({
|
||||||
|
String address,
|
||||||
|
Amount amount,
|
||||||
|
String memo,
|
||||||
|
})> sparkRecipientsWithFeeSubtracted = [];
|
||||||
|
final outputCount = (txData.recipients
|
||||||
|
?.where(
|
||||||
|
(e) => e.amount.raw > BigInt.zero,
|
||||||
|
)
|
||||||
|
.length ??
|
||||||
|
0) +
|
||||||
|
(txData.sparkRecipients?.length ?? 0);
|
||||||
|
final BigInt estimatedFee;
|
||||||
|
if (isSendAll) {
|
||||||
|
final estFee = LibSpark.estimateSparkFee(
|
||||||
|
privateKeyHex: privateKey.toHex,
|
||||||
|
index: kDefaultSparkIndex,
|
||||||
|
sendAmount: txAmount.raw.toInt(),
|
||||||
|
subtractFeeFromAmount: true,
|
||||||
|
serializedCoins: serializedCoins,
|
||||||
|
privateRecipientsCount: (txData.sparkRecipients?.length ?? 0),
|
||||||
|
);
|
||||||
|
estimatedFee = BigInt.from(estFee);
|
||||||
|
} else {
|
||||||
|
estimatedFee = BigInt.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (txData.sparkRecipients?.length ?? 0); i++) {
|
||||||
|
sparkRecipientsWithFeeSubtracted.add(
|
||||||
|
(
|
||||||
|
address: txData.sparkRecipients![i].address,
|
||||||
|
amount: Amount(
|
||||||
|
rawValue: txData.sparkRecipients![i].amount.raw -
|
||||||
|
(estimatedFee ~/ BigInt.from(outputCount)),
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
),
|
||||||
|
memo: txData.sparkRecipients![i].memo,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < (txData.recipients?.length ?? 0); i++) {
|
for (int i = 0; i < (txData.recipients?.length ?? 0); i++) {
|
||||||
if (txData.recipients![i].amount.raw == BigInt.zero) {
|
if (txData.recipients![i].amount.raw == BigInt.zero) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (txData.recipients![i].amount < cryptoCurrency.dustLimit) {
|
recipientsWithFeeSubtracted.add(
|
||||||
throw Exception("Output below dust limit");
|
(
|
||||||
}
|
address: txData.recipients![i].address,
|
||||||
//
|
amount: Amount(
|
||||||
// transparentOut += txData.recipients![i].amount.raw.toInt();
|
rawValue: txData.recipients![i].amount.raw -
|
||||||
txb.addOutput(
|
(estimatedFee ~/ BigInt.from(outputCount)),
|
||||||
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final scriptPubKey = btc.Address.addressToOutputScript(
|
||||||
txData.recipients![i].address,
|
txData.recipients![i].address,
|
||||||
txData.recipients![i].amount.raw.toInt(),
|
btcDartNetwork,
|
||||||
|
);
|
||||||
|
txb.addOutput(
|
||||||
|
scriptPubKey,
|
||||||
|
recipientsWithFeeSubtracted[i].amount.raw.toInt(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,12 +300,19 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
final spend = LibSpark.createSparkSendTransaction(
|
final spend = LibSpark.createSparkSendTransaction(
|
||||||
privateKeyHex: privateKey.toHex,
|
privateKeyHex: privateKey.toHex,
|
||||||
index: kDefaultSparkIndex,
|
index: kDefaultSparkIndex,
|
||||||
recipients: [],
|
recipients: txData.recipients
|
||||||
|
?.map((e) => (
|
||||||
|
address: e.address,
|
||||||
|
amount: e.amount.raw.toInt(),
|
||||||
|
subtractFeeFromAmount: isSendAll,
|
||||||
|
))
|
||||||
|
.toList() ??
|
||||||
|
[],
|
||||||
privateRecipients: txData.sparkRecipients
|
privateRecipients: txData.sparkRecipients
|
||||||
?.map((e) => (
|
?.map((e) => (
|
||||||
sparkAddress: e.address,
|
sparkAddress: e.address,
|
||||||
amount: e.amount.raw.toInt(),
|
amount: e.amount.raw.toInt(),
|
||||||
subtractFeeFromAmount: e.subtractFeeFromAmount,
|
subtractFeeFromAmount: isSendAll,
|
||||||
memo: e.memo,
|
memo: e.memo,
|
||||||
))
|
))
|
||||||
.toList() ??
|
.toList() ??
|
||||||
|
@ -246,6 +332,13 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
extractedTx.setPayload(spend.serializedSpendPayload);
|
extractedTx.setPayload(spend.serializedSpendPayload);
|
||||||
final rawTxHex = extractedTx.toHex();
|
final rawTxHex = extractedTx.toHex();
|
||||||
|
|
||||||
|
if (isSendAll) {
|
||||||
|
txData = txData.copyWith(
|
||||||
|
recipients: recipientsWithFeeSubtracted,
|
||||||
|
sparkRecipients: sparkRecipientsWithFeeSubtracted,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return txData.copyWith(
|
return txData.copyWith(
|
||||||
raw: rawTxHex,
|
raw: rawTxHex,
|
||||||
vSize: extractedTx.virtualSize(),
|
vSize: extractedTx.virtualSize(),
|
||||||
|
@ -279,8 +372,8 @@ mixin SparkInterface on Bip39HDWallet, ElectrumXInterface {
|
||||||
txHash: txHash,
|
txHash: txHash,
|
||||||
txid: txHash,
|
txid: txHash,
|
||||||
);
|
);
|
||||||
// mark utxos as used
|
// // mark utxos as used
|
||||||
await mainDB.putUTXOs(txData.usedUTXOs!);
|
// await mainDB.putUTXOs(txData.usedUTXOs!);
|
||||||
|
|
||||||
return txData;
|
return txData;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
|
Loading…
Reference in a new issue