1

Looks like there is no activity in caravan github repository so maybe someone here can help me with this issue. Already mentioned everything in the below link however my three basic questions are:

https://github.com/unchained-capital/caravan/issues/173

  1. How does tx size and fees calculation work in caravan?
  2. How does it work in other projects if there is any better implementation?
  3. Will there be a standard and easy approach to solve this problem in future which can be easily used by every bitcoin project?

Screenshot-Caravan

3
  • Is this question specifically about JavaScript?
    – Murch
    Aug 17, 2020 at 21:01
  • No. Caravan uses JS. Question is about tx size and fee calculation. Example: If I am using Nbitcoin and create a project using C# still I will have to figure out a way for calculating size and fees for transactions.
    – user103136
    Aug 17, 2020 at 21:08
  • 1
    Mh, I added a section to my answer to cover the topic more generally, but I also added the JavaScript tag here, because you are specifically asking about a JavaScript project which I answered for.
    – Murch
    Aug 17, 2020 at 21:33

2 Answers 2

3

The fee rate is pulled here:

export function fetchFeeEstimate(network, client) {
  if (client.type === BLOCK_EXPLORER) {
    return blockExplorerGetFeeEstimate(network);
  }
  return bitcoindEstimateSmartFee({
    ...bitcoindParams(client),
    ...{ numBlocks: 1 },
  });
}

(https://github.com/unchained-capital/caravan/blob/3514039983984e184e8babb6c61c21a46798fc70/src/blockchain.js#L97-L105)

It depends on if you are using a block explorer or a local bitcoind node. If using bitcoind, it uses the estimatesmartfee rpi cal:

export async function bitcoindEstimateSmartFee({ url, auth, numBlocks = 2 }) {
  const resp = await callBitcoind(url, auth, "estimatesmartfee", [numBlocks]);
  const feeRate = resp.result.feerate;
  return Math.ceil(feeRate * 100000);
}

(https://github.com/unchained-capital/caravan/blob/3514039983984e184e8babb6c61c21a46798fc70/src/bitcoind.js#L111-L115)

As for the transaction size/ total fee calculation, caravan uses estimateMultisigTransactionFee from unchained-bitcoin (https://github.com/unchained-capital/caravan/blob/fd214eb573c7185c01dfa2040aa914e87a0de359/src/actions/walletActions.js#L129)

Which depending on the transaction type (P2SH, P2WSH, P2SH-P2WSH) calls a transaction size estimator. The P2SH one is:

export function estimateMultisigP2SHTransactionVSize(config) {
  const baseSize = 41 * config.numInputs + 34 * config.numOutputs + 30;
  const signatureLength = 72 + 1; // approx including push byte
  const scriptOverhead = 4; 
  const keylength = 33 + 1;  // push byte
  const sigSize = signatureLength*config.m*config.numInputs + keylength*config.n*config.numInputs + scriptOverhead*config.numInputs;
  const vsize = baseSize + sigSize;
  return vsize;
}

(https://github.com/unchained-capital/unchained-bitcoin/blob/e9177e7171c3bf11ad5c245c7d633dac484f409c/src/p2sh.js#L27-L35)

Regarding your other questions, I look forward to hearing more about this. When we wrote this, I wasn't aware of unspents. It would be nice if there was a standard, well-tested package for calculating transaction fees.

Regarding other projects: Lily uses unchained-bitcoin: (https://github.com/KayBeSee/lily-wallet/blob/5945175f9e25cc7a8ff29159de39c228b79ef205/src/pages/Send/utils.js#L48) so it's the same as Caravan. I don't know what Casa does. I would assume BitGo uses unspents that Murch linked to. I'm pretty sure Electrum has it's own thing, but I haven't looked, I'd assume the same for Specter.

Hope this helps, sorry we didn't get back to you on the caravan issue, infomational tickets like that are low-priority for us right now.

1
  • Thanks for the detailed response. This will be helpful especially the transaction size calculation part.
    – user103136
    Aug 28, 2020 at 16:13
1

Generally, the vsize and weight of transactions is determined by counting the byte length of the serialized transaction, and by weighting the different parts of the transactions according to the rules of segwit. As most transactions use standard scripts, the input and output sizes are known in advance and the transaction size can be easily estimated from the count of inputs and outputs (and their script types). Since ECDSA signatures can have a slightly variable size, the transaction weight is usually estimated by using the largest possible weight (safest), or the expected weight. Signature size can be homogenized by using signature grinding.

According to its package.json, Caravan uses bitcoinjs-lib. bitcoinjs-lib is an established JavaScript library for address and transaction related tooling.

The code for calculating the weight of a transactions in bitcoinjs-lib is found in the Transaction class, specifically in the Transaction.weight() function. After the weight has been determined, the fee is calculated by weight and fee rate. As far as I am aware, bitcoinjs-lib does not provide its own fee rate estimates, so Caravan would likely rely on one of the many publicly available APIs to get a fee rate estimate.

BitGo provides an opensource library called unspents that calculates the virtual size of transactions in dimensions.ts. It's inspired by bitcoinjs-lib but has a special focus on multsig inputs. (Disclaimer: I have contributed code to unspents.)

There are similar libraries for other programming languages to provide tools for creating Bitcoin transactions and addresses.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.