getTransactionSegwitDigit method

Uint8List getTransactionSegwitDigit({
  1. required int txInIndex,
  2. required Script script,
  3. int sighash = SIGHASH_ALL,
  4. required BigInt amount,
})

returns the transaction input's segwit digest that is to be signed according to sighash.

txInIndex The index of the input that we wish to sign. script The scriptCode (template) that corresponds to the segwit, transaction output type that we want to spend. amount The amount of the UTXO to spend is included in the signature for segwit (in satoshis). sighash The type of the signature hash to be created.

Implementation

Uint8List getTransactionSegwitDigit(
    {required int txInIndex,
    required Script script,
    int sighash = SIGHASH_ALL,
    required BigInt amount}) {
  final tx = copy(this);
  Uint8List hashPrevouts = Uint8List(32);
  Uint8List hashSequence = Uint8List(32);
  Uint8List hashOutputs = Uint8List(32);
  int basicSigHashType = sighash & 0x1F;
  bool anyoneCanPay = (sighash & 0xF0) == SIGHASH_ANYONECANPAY;
  bool signAll = (basicSigHashType != SIGHASH_SINGLE) &&
      (basicSigHashType != SIGHASH_NONE);
  if (!anyoneCanPay) {
    hashPrevouts = Uint8List(0);
    for (final txin in tx.inputs) {
      Uint8List txidBytes =
          Uint8List.fromList(hexToBytes(txin.txId).reversed.toList());
      Uint8List txoutIndexBytes = packUint32LE(txin.txIndex);

      hashPrevouts = Uint8List.fromList(
          [...hashPrevouts, ...txidBytes, ...txoutIndexBytes]);
    }
    hashPrevouts = doubleHash(hashPrevouts);
  }

  if (!anyoneCanPay && signAll) {
    hashSequence = Uint8List(0);
    for (final i in tx.inputs) {
      hashSequence = Uint8List.fromList([...hashSequence, ...i.sequence]);
    }
    hashSequence = doubleHash(hashSequence);
  }
  if (signAll) {
    hashOutputs = Uint8List(0);
    for (final i in tx.outputs) {
      Uint8List amountBytes = packBigIntToLittleEndian(i.amount);
      Uint8List scriptBytes = i.scriptPubKey.toBytes();
      hashOutputs = Uint8List.fromList([
        ...hashOutputs,
        ...amountBytes,
        scriptBytes.length,
        ...scriptBytes
      ]);
    }
    hashOutputs = doubleHash(hashOutputs);
  } else if (basicSigHashType == SIGHASH_SINGLE &&
      txInIndex < tx.outputs.length) {
    final out = tx.outputs[txInIndex];
    Uint8List packedAmount = packBigIntToLittleEndian(out.amount);
    final scriptBytes = out.scriptPubKey.toBytes();
    Uint8List lenScriptBytes = Uint8List.fromList([scriptBytes.length]);
    hashOutputs = Uint8List.fromList(
        [...packedAmount, ...lenScriptBytes, ...scriptBytes]);
    hashOutputs = doubleHash(hashOutputs);
  }

  DynamicByteTracker txForSigning = DynamicByteTracker();
  txForSigning.add(version);
  txForSigning.add(hashPrevouts);
  txForSigning.add(hashSequence);
  final txIn = inputs[txInIndex];

  Uint8List txidBytes =
      Uint8List.fromList(hexToBytes(txIn.txId).reversed.toList());
  Uint8List txoutIndexBytes = packUint32LE(txIn.txIndex);
  txForSigning.add(Uint8List.fromList([...txidBytes, ...txoutIndexBytes]));
  txForSigning.add(Uint8List.fromList([script.toBytes().length]));
  txForSigning.add(script.toBytes());
  Uint8List packedAmount = packBigIntToLittleEndian(amount);
  txForSigning.add(packedAmount);
  txForSigning.add(txIn.sequence);
  txForSigning.add(hashOutputs);
  txForSigning.add(locktime);
  Uint8List packedSighash = packInt32LE(sighash);
  txForSigning.add(packedSighash);
  txForSigning.close();
  return doubleHash(txForSigning.toBytes());
}