Skip to content

Commit

Permalink
Merge pull request #46 from babylonchain/accurate-fee-calculation
Browse files Browse the repository at this point in the history
hotfix: Accurate fee calculation
  • Loading branch information
jrwbabylonlab authored Jun 28, 2024
2 parents 1393f43 + e1362ac commit f8f9f78
Show file tree
Hide file tree
Showing 18 changed files with 1,021 additions and 337 deletions.
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
npm test
npm run build
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export default {
preset: 'ts-jest',
testEnvironment: 'node',
setupFilesAfterEnv: ['./jest.setup.js'],
testMatch: ['**/tests/**/*.test.ts', '**/?(*.)+(spec|test).ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
transform: {
Expand Down
16 changes: 16 additions & 0 deletions jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const originalTest = global.test;
const NUM_ITERATIONS = 10;

global.test = (name, fn, timeout) => {
for (let i = 0; i < NUM_ITERATIONS; i++) {
originalTest(`${name} (iteration ${i + 1})`, fn, timeout);
}
};

const originalIt = global.it;

global.it = (name, fn, timeout) => {
for (let i = 0; i < NUM_ITERATIONS; i++) {
originalIt(`${name} (iteration ${i + 1})`, fn, timeout);
}
};
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "btc-staking-ts",
"version": "0.2.4",
"version": "0.2.5",
"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",
Expand All @@ -9,8 +9,8 @@
"scripts": {
"generate-types": "dts-bundle-generator -o ./dist/index.d.ts ./src/index.ts",
"build": "node build.js && npm run generate-types",
"format": "prettier --check \"src/**/*.ts\"",
"format:fix": "prettier --write \"src/**/*.ts\"",
"format": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
"format:fix": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
"lint": "eslint ./src --fix",
"prepare": "husky",
"prepublishOnly": "npm run build",
Expand Down
16 changes: 16 additions & 0 deletions src/constants/fee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Estimated size of a non-SegWit input in bytes
export const DEFAULT_INPUT_SIZE = 180;
// Estimated size of a P2WPKH input in bytes
export const P2WPKH_INPUT_SIZE = 68;
// Estimated size of a P2TR input in bytes
export const P2TR_INPUT_SIZE = 58;
// Estimated size of a transaction buffer in bytes
export const TX_BUFFER_SIZE_OVERHEAD = 11;
// Buffer for estimation accuracy when fee rate <= 2 sat/byte
export const LOW_RATE_ESTIMATION_ACCURACY_BUFFER = 30;
// Size of a Taproot output, the largest non-legacy output type
export const MAX_NON_LEGACY_OUTPUT_SIZE = 43;
// Buffer size for withdraw transaction fee calculation
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;
46 changes: 9 additions & 37 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import { UTXO } from "./types/UTXO";
import { PsbtTransactionResult } from "./types/transaction";
import { isValidBitcoinAddress } from "./utils/address";
import { initBTCCurve } from "./utils/curve";
import {
getEstimatedFee,
getStakingTxInputUTXOsAndFees,
inputValueSum,
} from "./utils/fee";
import { getStakingTxInputUTXOsAndFees, getWithdrawTxFee } from "./utils/fee";
import { inputValueSum } from "./utils/fee/utils";
import { buildStakingOutput } from "./utils/staking";
import { PK_LENGTH, StakingScriptData } from "./utils/stakingScript";

export { StakingScriptData, initBTCCurve };
Expand Down Expand Up @@ -84,14 +82,14 @@ export function stakingTransaction(
throw new Error("Invalid public key");
}

// Calculate the number of outputs based on the presence of the data embed script
// We have 2 outputs by default: staking output and change output
const numOutputs = scripts.dataEmbedScript ? 3 : 2;
// Build outputs and estimate the fee
const psbtOutputs = buildStakingOutput(scripts, network, amount);
const { selectedUTXOs, fee } = getStakingTxInputUTXOsAndFees(
network,
inputUTXOs,
amount,
feeRate,
numOutputs,
psbtOutputs,
);

// Create a partially signed transaction
Expand All @@ -112,33 +110,8 @@ export function stakingTransaction(
});
}

const scriptTree: Taptree = [
{
output: scripts.slashingScript,
},
[{ output: scripts.unbondingScript }, { output: scripts.timelockScript }],
];

// Create an pay-2-taproot (p2tr) output using the staking script
const stakingOutput = payments.p2tr({
internalPubkey,
scriptTree,
network,
});

// Add the staking output to the transaction
psbt.addOutput({
address: stakingOutput.address!,
value: amount,
});

if (scripts.dataEmbedScript) {
// Add the data embed output to the transaction
psbt.addOutput({
script: scripts.dataEmbedScript,
value: 0,
});
}
psbt.addOutputs(psbtOutputs);

// Add a change output only if there's any amount leftover from the inputs
const inputsSum = inputValueSum(selectedUTXOs);
Expand Down Expand Up @@ -362,8 +335,7 @@ function withdrawalTransaction(
if (outputValue < BTC_DUST_SAT) {
throw new Error("Output value is less than dust limit");
}
// withdraw tx always has 1 output only
const estimatedFee = getEstimatedFee(feeRate, psbt.txInputs.length, 1);
const estimatedFee = getWithdrawTxFee(feeRate);
const value = tx.outs[outputIndex].value - estimatedFee;
if (!value) {
throw new Error(
Expand Down
21 changes: 21 additions & 0 deletions src/types/psbtOutputs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { PsbtOutput } from "bip174/src/lib/interfaces";

export type PsbtOutputExtended =
| PsbtOutputExtendedAddress
| PsbtOutputExtendedScript;

interface PsbtOutputExtendedAddress extends PsbtOutput {
address: string;
value: number;
}

interface PsbtOutputExtendedScript extends PsbtOutput {
script: Buffer;
value: number;
}

export const isPsbtOutputExtendedAddress = (
output: PsbtOutputExtended,
): output is PsbtOutputExtendedAddress => {
return (output as PsbtOutputExtendedAddress).address !== undefined;
};
117 changes: 0 additions & 117 deletions src/utils/fee.ts

This file was deleted.

Loading

0 comments on commit f8f9f78

Please sign in to comment.