Skip to content
This repository was archived by the owner on Feb 8, 2026. It is now read-only.

Commit fdd540e

Browse files
authored
fix(send): fee calculation for tx w/ p2sh input addresses (#897)
* fix(send): fee calculation for tx w/ p2sh input addresses * fix(send): update test total fee
1 parent 08fb199 commit fdd540e

3 files changed

Lines changed: 42 additions & 30 deletions

File tree

__tests__/wallet-send.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ describe('Wallet - new wallet, send and receive', () => {
171171

172172
const tx13 =
173173
store.getState().wallet.wallets.wallet0.transaction.bitcoinRegtest;
174-
expect(tx13?.satsPerByte).toBe(3);
175-
expect(tx13?.fee).toBe(900);
174+
expect(tx13.satsPerByte).toBe(3);
175+
expect(tx13.fee).toBe(423);
176176

177177
res = validateTransaction(tx13);
178178
if (res.isErr()) {

src/store/types/wallet.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,16 @@ export type TBitcoinLabel =
5151
export type TTicker = 'BTC' | 'tBTC';
5252

5353
export type TGetByteCountInput =
54-
| 'MULTISIG-P2SH'
55-
| 'MULTISIG-P2WSH'
56-
| 'MULTISIG-P2SH-P2WSH'
54+
| `MULTISIG-P2SH:${number}-${number}`
55+
| `MULTISIG-P2WSH:${number}-${number}`
56+
| `MULTISIG-P2SH-P2WSH:${number}-${number}`
57+
| 'P2SH-P2WPKH'
5758
| 'P2PKH'
59+
| 'p2pkh'
5860
| 'P2WPKH'
59-
| 'P2SH-P2WPKH'
6061
| 'p2wpkh'
61-
| 'p2sh'
62-
| 'p2pkh'
63-
| string; //Unsure how to account for multisig variations (ex. 'MULTISIG-P2SH:2-4')
62+
| 'P2SH'
63+
| 'p2sh';
6464

6565
export type TGetByteCountOutput =
6666
| 'P2SH'

src/utils/wallet/transactions.ts

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import {
2828
EAddressType,
2929
TGetByteCountInputs,
3030
TGetByteCountOutputs,
31+
TGetByteCountInput,
32+
TGetByteCountOutput,
3133
TWalletName,
3234
} from '../../store/types/wallet';
3335
import {
@@ -194,17 +196,32 @@ export const getByteCount = (
194196
let inputCount = 0;
195197
let outputCount = 0;
196198
// assumes compressed pubkeys in all cases.
197-
let types = {
199+
const types: {
200+
inputs: {
201+
[key in TGetByteCountInput]: number;
202+
};
203+
multiSigInputs: {
204+
'MULTISIG-P2SH': number;
205+
'MULTISIG-P2WSH': number;
206+
'MULTISIG-P2SH-P2WSH': number;
207+
};
208+
outputs: {
209+
[key in TGetByteCountOutput]: number;
210+
};
211+
} = {
198212
inputs: {
199-
'MULTISIG-P2SH': 49 * 4,
200-
'MULTISIG-P2WSH': 6 + 41 * 4,
201-
'MULTISIG-P2SH-P2WSH': 6 + 76 * 4,
202-
P2PKH: 148 * 4,
203213
P2WPKH: 108 + 41 * 4,
204-
'P2SH-P2WPKH': 108 + 64 * 4,
205214
p2wpkh: 108 + 41 * 4 + 1,
206-
p2sh: 108 + 64 * 4 + 1,
215+
P2PKH: 148 * 4,
207216
p2pkh: 148 * 4 + 1,
217+
P2SH: 108 + 64 * 4,
218+
p2sh: 108 + 64 * 4 + 1,
219+
'P2SH-P2WPKH': 108 + 64 * 4,
220+
},
221+
multiSigInputs: {
222+
'MULTISIG-P2SH': 49 * 4,
223+
'MULTISIG-P2WSH': 6 + 41 * 4,
224+
'MULTISIG-P2SH-P2WSH': 6 + 76 * 4,
208225
},
209226
outputs: {
210227
P2SH: 32 * 4,
@@ -252,7 +269,7 @@ export const getByteCount = (
252269
return parseInt(item);
253270
});
254271

255-
totalWeight += types.inputs[newKey] * addressTypeCount;
272+
totalWeight += types.multiSigInputs[newKey] * addressTypeCount;
256273
const multiplyer = newKey === 'MULTISIG-P2SH' ? 4 : 1;
257274
totalWeight +=
258275
(73 * mAndN[0] + 34 * mAndN[1]) * multiplyer * addressTypeCount;
@@ -281,16 +298,11 @@ export const getByteCount = (
281298
totalWeight += varIntLength(inputCount) * 4;
282299
totalWeight += varIntLength(outputCount) * 4;
283300

284-
let messageByteCount = 0;
285-
try {
286-
messageByteCount = message?.length ?? 0;
287-
//Multiply by 2 to help ensure Electrum servers will broadcast the tx.
288-
messageByteCount = messageByteCount * 2;
289-
} catch {}
290-
const res = Math.ceil(totalWeight / 4) + messageByteCount;
291-
return res > ETransactionDefaults.recommendedBaseFee
292-
? res
293-
: ETransactionDefaults.recommendedBaseFee;
301+
let messageByteCount = message?.length ?? 0;
302+
//Multiply by 2 to help ensure Electrum servers will broadcast the tx.
303+
messageByteCount = messageByteCount * 2;
304+
305+
return Math.ceil(totalWeight / 4) + messageByteCount;
294306
} catch (e) {
295307
return ETransactionDefaults.recommendedBaseFee;
296308
}
@@ -304,7 +316,7 @@ export const constructByteCountParam = (
304316
addresses: string[],
305317
): TGetByteCountInputs | TGetByteCountOutputs => {
306318
try {
307-
if (!addresses || addresses.length <= 0) {
319+
if (addresses.length <= 0) {
308320
return { P2WPKH: 0 };
309321
}
310322
let param: TGetByteCountOutputs = {};
@@ -359,11 +371,11 @@ export const getTotalFee = ({
359371
}
360372

361373
const inputs = transaction.inputs || [];
362-
let outputs: IOutput[] = transaction.outputs || [];
374+
const outputs = transaction.outputs || [];
363375
const changeAddress = transaction.changeAddress;
364376

365377
//Group all input & output addresses into their respective array.
366-
const inputAddresses = inputs.map((input) => input.address) || [];
378+
const inputAddresses = inputs.map((input) => input.address);
367379
const outputAddresses =
368380
outputs.map((output) => {
369381
if (output.address) {

0 commit comments

Comments
 (0)