CoinSelection constructor

CoinSelection({
  1. int version = Transaction.currentVersion,
  2. required Iterable<InputCandidate> selected,
  3. required Iterable<Output> recipients,
  4. required Program changeProgram,
  5. required BigInt feePerKb,
  6. required BigInt minFee,
  7. required BigInt minChange,
  8. int locktime = 0,
})

Selects all the inputs from selected to send to the recipients outputs and provide change to the changeProgram. The feePerKb specifies the required fee in sats per KB with a minimum fee specified with minFee. The minChange is the minimum allowed change.

Implementation

CoinSelection({
  this.version = Transaction.currentVersion,
  required Iterable<InputCandidate> selected,
  required Iterable<Output> recipients,
  required this.changeProgram,
  required this.feePerKb,
  required this.minFee,
  required this.minChange,
  this.locktime = 0,
}) : selected = List.unmodifiable(selected),
  recipients = List.unmodifiable(recipients) {

  if (selected.any((candidate) => candidate.input.signedSize == null)) {
    throw ArgumentError("Cannot select inputs without known max signed size");
  }

  // Get input and recipient values
  inputValue = selected
    .fold(BigInt.zero, (acc, candidate) => acc + candidate.value);
  recipientValue = recipients
    .fold(BigInt.zero, (acc, output) => acc + output.value);

  // Get unchanging size
  final int fixedSize
    // Version and locktime
    = 8
    // Fully signed inputs
    + MeasureWriter.varIntSizeOfInt(selected.length)
    + selected.fold(0, (acc, candidate) => acc + candidate.input.signedSize!);

  // Determine size and fee with change
  final sizeWithChange = _sizeGivenChange(fixedSize, true);
  final feeWithChange = _feeForSize(sizeWithChange);
  final includedChangeValue = inputValue - recipientValue - feeWithChange;

  // If change is under the required minimum, remove the change output
  if (includedChangeValue.compareTo(minChange) < 0) {

    final changelessSize = _sizeGivenChange(fixedSize, false);
    final feeForSize = _feeForSize(changelessSize);
    final excess = inputValue - recipientValue - feeForSize;

    if (!excess.isNegative) {
      // Exceeded without change. Fee is the input value minus the recipient
      // value
      signedSize = changelessSize;
      fee = inputValue - recipientValue;
      changeValue = BigInt.zero;
      return;
    }
    // Else haven't met requirement

  }

  // Either haven't met requirement, or have met requirement with change so
  // provide details of change-containing transaction
  signedSize = sizeWithChange;
  fee = feeWithChange;
  changeValue = includedChangeValue;

}