What changed, and why it matters
This commit fixes how the Stack Wallet calculates the size of a special 'Spark Name' fee script when building cryptocurrency transactions. Previously, the wallet appears to have used a fixed estimate (noProofNameTxData!.size) and did not account for the extra bytes added by embedding the Spark Name data into the output script. The patch now measures the actual increase in script size and adds that delta to the transaction size used for fee estimation. If left unfixed, transactions with Spark Names could have had fees that did not cover the real transaction size, potentially causing the transaction to be rejected, delayed, or underpaid.
Treat as a routine correctness fix. Verify that the new delta calculation covers all Spark Name output paths and that the updated test passes. Consider whether any previously created Spark Name transactions may have been broadcast with underestimated fees and monitor for stuck transactions. No immediate emergency response is indicated from the diff alone.
Security signals we found
Transaction fee underestimation due to missing script size delta
Potential transaction propagation/mining failure from insufficient fee
Spark Name output script size not fully accounted for in additionalTxSize
Test added/updated to assert exact script length and size delta
Evidence from the diff
In spark_interface.dart, the code builds transaction outputs and, when txData.sparkNameInfo is present, wraps the base scriptPubKey with sparkNameFeeScript(), which appends name/spark-address data. Before this commit, the additionalTxSize passed to the fee/transaction finalization step was noProofNameTxData!.size alone, ignoring the actual byte growth of the output script. The patch introduces sparkNameFeeScriptSizeDelta, computed as scriptPubKey.length - baseScript.length for each Spark Name output, and adds it to additionalTxSize. A test is updated to assert the delta is 155 bytes and the total fee script length is 180 bytes. This is a sizing/fee-calculation correctness fix; it does not by itself change authorization logic or cryptographic validation.
Changed components
lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dartSpark Name transaction/fee construction flowtest/wallets/spark_name_fee_test.dartInspect captured patch +5 / −1
diff --git a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart
index fd52362..bf3e627 100644
--- a/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart
+++ b/lib/wallets/wallet/wallet_mixin_interfaces/spark_interface.dart
@@ -721,6 +721,7 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
final List<InputV2> tempInputs = [];
final List<OutputV2> tempOutputs = [];
+ var sparkNameFeeScriptSizeDelta = 0;
for (int i = 0; i < (txData.recipients?.length ?? 0); i++) {
if (txData.recipients![i].amount.raw == BigInt.zero) {
continue;
@@ -741,11 +742,13 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
_bitcoinDartNetwork,
);
if (txData.sparkNameInfo != null) {
+ final baseScript = scriptPubKey;
scriptPubKey = sparkNameFeeScript(
baseScript: scriptPubKey,
name: txData.sparkNameInfo!.name,
sparkAddress: txData.sparkNameInfo!.sparkAddress.value,
);
+ sparkNameFeeScriptSizeDelta += scriptPubKey.length - baseScript.length;
}
txb.addOutput(
scriptPubKey,
@@ -851,7 +854,7 @@ mixin SparkInterface<T extends ElectrumXCurrencyInterface>
txHash: extractedTx.getHash(),
additionalTxSize: txData.sparkNameInfo == null
? 0
- : noProofNameTxData!.size,
+ : noProofNameTxData!.size + sparkNameFeeScriptSizeDelta,
));
for (final outputScript in spend.outputScripts) {
diff --git a/test/wallets/spark_name_fee_test.dart b/test/wallets/spark_name_fee_test.dart
index a15ed3f..0608fa9 100644
--- a/test/wallets/spark_name_fee_test.dart
+++ b/test/wallets/spark_name_fee_test.dart
@@ -19,6 +19,7 @@ void main() {
sparkAddress: List.filled(144, 'a').join(),
);
+ expect(feeScript.length - baseScript.length, 155);
expect(feeScript.length, 180);
expect(feeScript[25], OP_SPARKNAMEID);
expect(feeScript[32], OP_DROP);
Why this scored 42/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.