From 8dafe14d123e09eda2de607958b12df6c18b2ecb Mon Sep 17 00:00:00 2001 From: wjrjerome Date: Tue, 2 Jul 2024 00:42:46 +1000 Subject: [PATCH] fix: add op_return value size when calculating fee --- package-lock.json | 4 ++-- package.json | 4 ++-- src/constants/fee.ts | 5 +++++ src/utils/fee/index.ts | 4 +++- tests/utils/fee/stakingtxFee.test.ts | 14 +++++++------- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index eeb6f88..bb1a587 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "btc-staking-ts", - "version": "0.2.5", + "version": "0.2.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "btc-staking-ts", - "version": "0.2.5", + "version": "0.2.8", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3", diff --git a/package.json b/package.json index 2198d2d..460051b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "btc-staking-ts", - "version": "0.2.7", + "version": "0.2.8", "description": "Library exposing methods for the creation and consumption of Bitcoin transactions pertaining to Babylon's Bitcoin Staking protocol. Experimental version, should not be used for production purposes or with real funds.", "module": "dist/index.js", "main": "dist/index.cjs", @@ -60,4 +60,4 @@ "@bitcoin-js/tiny-secp256k1-asmjs": "^2.2.3", "bitcoinjs-lib": "^6.1.5" } -} +} \ No newline at end of file diff --git a/src/constants/fee.ts b/src/constants/fee.ts index 0590725..f68caf6 100644 --- a/src/constants/fee.ts +++ b/src/constants/fee.ts @@ -14,3 +14,8 @@ export const MAX_NON_LEGACY_OUTPUT_SIZE = 43; export const WITHDRAW_TX_BUFFER_SIZE = 17; // Threshold for wallet relay fee rate. Different buffer fees are used based on this threshold export const WALLET_RELAY_FEE_RATE_THRESHOLD = 2; +// Estimated size of the OP_RETURN output value in bytes +export const OP_RETURN_OUTPUT_VALUE_SIZE = 8; +// Because our OP_RETURN data will always be less than 80 bytes, which is less than 0xfd (253), +// the value serialization size will always be 1 byte. +export const OP_RETURN_VALUE_SERIALIZE_SIZE = 1; diff --git a/src/utils/fee/index.ts b/src/utils/fee/index.ts index 5420ebc..d4ae2ab 100644 --- a/src/utils/fee/index.ts +++ b/src/utils/fee/index.ts @@ -3,6 +3,8 @@ import { BTC_DUST_SAT } from "../../constants/dustSat"; import { LOW_RATE_ESTIMATION_ACCURACY_BUFFER, MAX_NON_LEGACY_OUTPUT_SIZE, + OP_RETURN_OUTPUT_VALUE_SIZE, + OP_RETURN_VALUE_SERIALIZE_SIZE, P2TR_INPUT_SIZE, TX_BUFFER_SIZE_OVERHEAD, WALLET_RELAY_FEE_RATE_THRESHOLD, @@ -141,7 +143,7 @@ const getEstimatedSize = ( ? address.toOutputScript(output.address, network) : output.script; if (isOP_RETURN(script)) { - return acc + script.length; + return acc + script.length + OP_RETURN_OUTPUT_VALUE_SIZE + OP_RETURN_VALUE_SERIALIZE_SIZE; } return acc + MAX_NON_LEGACY_OUTPUT_SIZE; }, 0); diff --git a/tests/utils/fee/stakingtxFee.test.ts b/tests/utils/fee/stakingtxFee.test.ts index 435fef8..d08e6c4 100644 --- a/tests/utils/fee/stakingtxFee.test.ts +++ b/tests/utils/fee/stakingtxFee.test.ts @@ -96,7 +96,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { 1, outputs, ); - expect(result.fee).toBe(316); // This number is calculated manually + expect(result.fee).toBe(325); // This number is calculated manually expect(result.selectedUTXOs.length).toEqual(2); result = getStakingTxInputUTXOsAndFees( @@ -106,7 +106,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { 2, outputs, ); - expect(result.fee).toBe(516); // This number is calculated manually + expect(result.fee).toBe(534); // This number is calculated manually expect(result.selectedUTXOs.length).toEqual(2); // Once fee rate is set to 3, the fee will be calculated with addition of TX_BUFFER_SIZE_OVERHEAD * feeRate @@ -117,7 +117,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { 3, outputs, ); - expect(result.fee).toBe(729); // This number is calculated manually + expect(result.fee).toBe(756); // This number is calculated manually expect(result.selectedUTXOs.length).toEqual(2); }); @@ -149,7 +149,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { 1, outputs, ); - expect(result.fee).toBe(336); // This number is calculated manually + expect(result.fee).toBe(345); // This number is calculated manually expect(result.selectedUTXOs.length).toEqual(2); }); @@ -163,7 +163,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { txid: dataGenerator.generateRandomTxId(), vout: Math.floor(Math.random() * 10), scriptPubKey: nativeSegwit.scriptPubKey, - value: 1000, + value: 1009, }, { txid: dataGenerator.generateRandomTxId(), @@ -181,7 +181,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { 1, outputs, ); - expect(result.fee).toBe(293); // This is the fee for 2 inputs and 2 outputs without change + expect(result.fee).toBe(302); // This is the fee for 2 inputs and 2 outputs without change expect(result.selectedUTXOs.length).toEqual(2); }); @@ -213,7 +213,7 @@ testingNetworks.forEach(({ networkName, network, dataGenerator }) => { 1, outputs, ); - expect(result.fee).toBe(225); + expect(result.fee).toBe(234); expect(result.selectedUTXOs.length).toEqual(1); }); });