Skip to content

Commit

Permalink
fix(send): add witness data byte count for p2sh tx (synonymdev#903)
Browse files Browse the repository at this point in the history
* fix(send): add witness data byte count for p2sh tx

* fix(send): update test hex

* fix(send): update test id
  • Loading branch information
pwltr authored Feb 22, 2023
1 parent dbe9a74 commit 2fc35e9
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 49 deletions.
4 changes: 2 additions & 2 deletions __tests__/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ describe('On chain transactions', () => {
}

expect(res.value.hex).toEqual(
'020000000001020c0eab3149ba3ed7abd8f4c98eabe2cbb2b7c3590404b66ca0f01addf61ec67100000000000000000051bd848851cadb71bf34e6e0e46b0c4214c2d06ccc1d5ca0f5baefdcf862692000000000000000000002112700000000000017a9147a40d326e4de19353e2bf8b3f15b395c88b2d2418791cc010000000000160014669a9323418693b81d44c19da7b1fe7911b2142902483045022100b24214eccadb5d7754735e32150e44f664ad588e66a2415398f2341e711c06a2022028a87680c01eaa578a22b80ff2d136e7971f69ff7b6dcd5ac759382d5c20addb01210318cb16a8e659f378002e75abe93f064c4ebcd62576bc15019281b635f96840a80247304402202bef617b03c4f9f8585fec97123659074c2e9cc81385288315074dac5c5b643b02203fbfaaf6f998d7f9ac19a49c3ca31487f105899d747993f53fbb7eb6817a279b012102bb6083f2571ecd26f68edeae341c0700463349a84b2044c271e061e813e0cd0300000000',
'020000000001020c0eab3149ba3ed7abd8f4c98eabe2cbb2b7c3590404b66ca0f01addf61ec67100000000000000000051bd848851cadb71bf34e6e0e46b0c4214c2d06ccc1d5ca0f5baefdcf862692000000000000000000002112700000000000017a9147a40d326e4de19353e2bf8b3f15b395c88b2d241876ecd010000000000160014669a9323418693b81d44c19da7b1fe7911b2142902483045022100e5bf3be5b8626fc72447cee78684416b8e23b905087c8dfadb69732124fd5ba6022021fa2fe097afde801ae0495f95a11b0bfc8273804b88ed63861d72a16548593101210318cb16a8e659f378002e75abe93f064c4ebcd62576bc15019281b635f96840a802483045022100ab9a47bf65d5855e19badaf60b6e74e454b3bcc0af3c7f465b32070a06781b920220336169c94789a4a17b6e22f9a094f3775da96c82f9c4ac57ebcea8e90885bf16012102bb6083f2571ecd26f68edeae341c0700463349a84b2044c271e061e813e0cd0300000000',
);

expect(res.value.id).toEqual(
'5354adb3f4549da123802f46817e0a3ce6fb5108b056636674721e4a693a59ff',
'4155049f78ff36c13dd9ca4c657799600115579a86bb465601ec8ca0af9f6982',
);
});
});
62 changes: 15 additions & 47 deletions src/utils/wallet/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ const setReplaceByFee = ({
};

/*
Source:
https://gist.github.com/junderw/b43af3253ea5865ed52cb51c200ac19c
Adapted from: https://gist.github.com/junderw/b43af3253ea5865ed52cb51c200ac19c
Usage:
getByteCount({'MULTISIG-P2SH:2-4':45},{'P2PKH':1}) Means "45 inputs of P2SH Multisig and 1 output of P2PKH"
getByteCount({'P2PKH':1,'MULTISIG-P2SH:2-3':2},{'P2PKH':2}) means "1 P2PKH input and 2 Multisig P2SH (2 of 3) inputs along with 2 P2PKH outputs"
Expand All @@ -191,11 +190,10 @@ export const getByteCount = (
message?: string,
): number => {
try {
let totalWeight = 0;
// Base transaction weight
let totalWeight = 40;
let hasWitness = false;
let inputCount = 0;
let outputCount = 0;
// assumes compressed pubkeys in all cases.

const types: {
inputs: {
[key in TGetByteCountInput]: number;
Expand Down Expand Up @@ -240,18 +238,6 @@ export const getByteCount = (
}
};

const varIntLength = (number: number): number => {
checkUInt53(number);

return number < 0xfd
? 1
: number <= 0xffff
? 3
: number <= 0xffffffff
? 5
: 9;
};

const inputKeys = objectKeys(inputs);
inputKeys.forEach(function (key) {
const input = inputs[key]!;
Expand All @@ -264,10 +250,7 @@ export const getByteCount = (
throw new Error('invalid input: ' + key);
}
const newKey = keyParts[0];
const mAndN = keyParts[1].split('-').map(function (item) {
// eslint-disable-next-line radix
return parseInt(item);
});
const mAndN = keyParts[1].split('-').map((item) => parseInt(item, 10));

totalWeight += types.multiSigInputs[newKey] * addressTypeCount;
const multiplyer = newKey === 'MULTISIG-P2SH' ? 4 : 1;
Expand All @@ -276,8 +259,7 @@ export const getByteCount = (
} else {
totalWeight += types.inputs[key] * addressTypeCount;
}
inputCount += addressTypeCount;
if (key.indexOf('W') >= 0) {
if (['p2sh', 'P2SH', 'P2SH-P2WPKH', 'p2wpkh', 'P2WPKH'].includes(key)) {
hasWitness = true;
}
});
Expand All @@ -287,22 +269,19 @@ export const getByteCount = (
const output = outputs[key]!;
checkUInt53(output);
totalWeight += types.outputs[key] * output;
outputCount += output;
});

if (hasWitness) {
totalWeight += 2;
}

totalWeight += 8 * 4;
totalWeight += varIntLength(inputCount) * 4;
totalWeight += varIntLength(outputCount) * 4;

let messageByteCount = message?.length ?? 0;
//Multiply by 2 to help ensure Electrum servers will broadcast the tx.
messageByteCount = messageByteCount * 2;
if (message?.length) {
// Multiply by 2 to help ensure Electrum servers will broadcast the tx.
totalWeight += message.length * 2;
}

return Math.ceil(totalWeight / 4) + messageByteCount;
// Convert from Weight Units to virtual size
return Math.ceil(totalWeight / 4);
} catch (e) {
return ETransactionDefaults.recommendedBaseFee;
}
Expand Down Expand Up @@ -392,15 +371,11 @@ export const getTotalFee = ({
const outputParam = constructByteCountParam(outputAddresses);
//Increase P2WPKH output address by one for lightning funding calculation.
if (fundingLightning) {
outputParam.P2WPKH = (outputParam?.P2WPKH || 0) + 1;
outputParam.P2WPKH = (outputParam.P2WPKH || 0) + 1;
}

const transactionByteCount =
getByteCount(inputParam, outputParam, message) || fallBackFee;
const totalFee = transactionByteCount * Number(satsPerByte);
return totalFee > fallBackFee || Number.isNaN(totalFee)
? totalFee
: fallBackFee;
const transactionByteCount = getByteCount(inputParam, outputParam, message);
return transactionByteCount * Number(satsPerByte);
} catch {
return Number(satsPerByte) * fallBackFee || fallBackFee;
}
Expand Down Expand Up @@ -1399,9 +1374,6 @@ export const validateTransaction = (
if (!transaction?.fee) {
return err('No transaction fee provided.');
}
if (transaction.fee < baseFee) {
return err(`Transaction fee must be larger than ${baseFee}.`);
}
if (
!transaction?.outputs ||
transaction.outputs?.length < 1 ||
Expand Down Expand Up @@ -1458,10 +1430,6 @@ export const validateTransaction = (
return err(outputsReduce.error.message);
}

const fee = transaction.fee;
if (fee < baseFee) {
return err(`Fee must be larger than ${baseFee}`);
}
return ok('Transaction is valid.');
} catch (e) {
return err(e);
Expand Down

0 comments on commit 2fc35e9

Please sign in to comment.