bitcoinjs / coinselect

An unspent transaction output (UTXO) selection module for bitcoin.
MIT License
178 stars 101 forks source link

inputs and outputs returning unidefined when pending balance #62

Closed robson036 closed 3 years ago

robson036 commented 3 years ago

Hi, everyone. I'm in trouble to make bitcoin transactions. After sending a transaction, the pending balance stays negative untill the transaction be confirmed. But, if I try to send other transaction, the variables inputs and outputs returns undefined from coinselect.

My code is below:

  addressesWithUtxo = [],
  targetAddress,
  feeRate,
  changeAddress,
  mnemonic
) => {
  const utxos = await fetchUtxos(addressesWithUtxo);

  // If the are pending transaction, inputs and outputs returns as undefined
  let { inputs, outputs, fee } = coinSelect(utxos, [targetAddress], feeRate);

  console.log('Fee aquii => ', fee);

  var bitcoinNetwork = network;

  const seed = await bip39.mnemonicToSeed(mnemonic);
  const hdRoot = bitcoin.bip32.fromSeed(seed, bitcoinNetwork);

  // .inputs and .outputs will be undefined if no solution was found
  if (!inputs || !outputs) return;

  const psbt = new bitcoin.Psbt({ network });
  // { network: network }
  const derivationPath = "m/84'/0'/0'";

  for (const input of inputs) {
    const inputPublicKey = findPublicKeyForAddress(
      input.address,
      addressesWithUtxo
    );

    if (!inputPublicKey) {
      throw new Error('Could not find public key for input');
    }

    const p2sh = bitcoin.payments.p2sh({
      redeem: bitcoin.payments.p2wpkh({ pubkey: inputPublicKey })
    });

    psbt.addInput({
      hash: input.txid,
      index: input.vout,
      bip32Derivation: [
        {
          masterFingerprint: hdRoot.fingerprint,
          path: `${derivationPath}/${input.derivationPath}`,
          pubkey: inputPublicKey
        }
      ],
      witnessUtxo: {
        script: p2sh.output,
        value: input.value
      },
      redeemScript: p2sh.redeem.output
    });
  }

  for (const output of outputs) {
    if (!output.address) {
      output.address = changeAddress;
    }

    psbt.addOutput({
      address: output.address,
      value: output.value
    });

    console.log({
      address: output.address,
      value: output.value
    });
  }

  await psbt.signAllInputsHDAsync(hdRoot);

  // console.log(psbt.toBase64());

  const transaction = psbt.finalizeAllInputs().extractTransaction();

  // console.log('Transação => ', transaction);
  // console.log('Tohex => ', transaction.toHex());

  return { transaction, utxos, targetAddress, fee };
};
junderw commented 3 years ago

Please post the contents of utxos.

robson036 commented 3 years ago

Please post the contents of utxos.

Hi, junderw. There is the content:

[{"txid":"ee4f8fda16b949fd0fb3920b6e25adc48d4a961472c7fc7c57b6d2b13542fa69","vout":0,"status":{"confirmed":true,"block_height":1901795,"block_hash":"000000000000000d9b875e93c297f45dae3bc6c098a400874bc3f7b289db25ff","block_time":1609514179},"value":40,"address":"2NF7XGr6neP97gQeFoqxovBSWP84aMKZULt","derivationPath":"0/0"},{"txid":"15cb8112be45be5f5fdf58bf8aa37f63f3e3e2d48eebe087a9eba56f20b2e78a","vout":0,"status":{"confirmed":true,"block_height":1901795,"block_hash":"000000000000000d9b875e93c297f45dae3bc6c098a400874bc3f7b289db25ff","block_time":1609514179},"value":40,"address":"2NF7XGr6neP97gQeFoqxovBSWP84aMKZULt","derivationPath":"0/0"},{"txid":"d2dde0f78d8eab44591fce4a5d6938d535e3ceef85c345c5644166b03aeaf9c7","vout":0,"status":{"confirmed":true,"block_height":1901643,"block_hash":"000000002d75415ef50f794159316b4840d8a96739ccf158e109e6041f629260","block_time":1609440171},"value":50,"address":"2NF7XGr6neP97gQeFoqxovBSWP84aMKZULt","derivationPath":"0/0"},{"txid":"bec9c1e9d15fb22b8779927814f7c0fce1cc55c0a6832a7434ec96074eb2b94d","vout":0,"status":{"confirmed":true,"block_height":1901643,"block_hash":"000000002d75415ef50f794159316b4840d8a96739ccf158e109e6041f629260","block_time":1609440171},"value":50,"address":"2NF7XGr6neP97gQeFoqxovBSWP84aMKZULt","derivationPath":"0/0"},{"txid":"2180b4acdfb49fb0f5fd3f3b1d717ac2aab969124c5ec528555ef4c15555ea1c","vout":0,"status":{"confirmed":false},"value":40,"address":"2NF7XGr6neP97gQeFoqxovBSWP84aMKZULt","derivationPath":"0/0"},{"txid":"db977bbc323e504e77f6cd5d3e25e0e8457988137c9dfef05a21c11627240e0b","vout":0,"status":{"confirmed":false},"value":40,"address":"2NF7XGr6neP97gQeFoqxovBSWP84aMKZULt","derivationPath":"0/0"}]

junderw commented 3 years ago

Problems:

  1. You only have 260 satoshis total. If the send amount is higher than the total amount of all utxos minus fees it will return nothing.
  2. You can't use an array of address strings for outputs. [targetAddress] is wrong. You need an array of objects with a value attribute. ie. coinSelect(utxos, [{ address: 'a', value: 168 }], 0) you can.

So currently, since you have such little money, the only possible output is with feeRate 0, and your target array value total must be <= 260 (I put 168 as an example)

robson036 commented 3 years ago

Problems:

  1. You only have 260 satoshis total. If the send amount is higher than the total amount of all utxos minus fees it will return nothing.
  2. You can't use an array of address strings for outputs. [targetAddress] is wrong. You need an array of objects with a value attribute. ie. coinSelect(utxos, [{ address: 'a', value: 168 }], 0) you can.

So currently, since you have such little money, the only possible output is with feeRate 0, and your target array value total must be <= 260 (I put 168 as an example)

Variable targetAddress is an object that contains the string address and value: image

The total balance minus the outstanding balance is sufficient to make the transaction image

In this example I'm trying to send 40 satoshis with 40/byte fee rate.

junderw commented 3 years ago

The total balance minus the outstanding balance is sufficient to make the transaction

This information is irrelevant to this library if that is not reflected in the utxos array.

Your utxos array only had 260 satoshis total.

The issue is not with this library, it is with whatever API you used to get your utxo info.