largestFirst function

Future<Result<CoinSelection, CoinSelectionError>> largestFirst({
  1. required List<WalletTransaction> unspentInputsAvailable,
  2. required List<MultiAssetRequest> outputsRequested,
  3. required Set<ShelleyAddress> ownedAddresses,
  4. int coinSelectionLimit = defaultCoinSelectionLimit,
  5. bool logSelection = false,
})

Implementation

Future<Result<CoinSelection, CoinSelectionError>> largestFirst({
  required List<WalletTransaction> unspentInputsAvailable,
  required List<MultiAssetRequest> outputsRequested,
  required Set<ShelleyAddress> ownedAddresses,
  int coinSelectionLimit = defaultCoinSelectionLimit,
  bool logSelection = false,
}) async {
  final logger = Logger();
  if (outputsRequested.isEmpty) {
    return Err(CoinSelectionError(
        reason: CoinSelectionErrorEnum.inputCountInsufficient,
        message: "can't create an empty transaction"));
  }
  const String hardCodedUnit = lovelaceHex;
  Coin amount = 0;
  for (final reqest in outputsRequested) {
    if (reqest.policyId == '') {
      for (final asset in reqest.assets) {
        if (asset.name == lovelaceHex) {
          amount = asset.value;
        } else {
          return Err(CoinSelectionError(
            reason: CoinSelectionErrorEnum.unsupported,
            message: "only support ADA transactions at this time",
          ));
        }
      }
    } else {
      return Err(CoinSelectionError(
        reason: CoinSelectionErrorEnum.unsupported,
        message: "only support ADA transactions at this time",
      ));
    }
  }
  if (amount <= 0) {
    return Err(CoinSelectionError(
      reason: CoinSelectionErrorEnum.inputValueInsufficient,
      message: "transactions must be greater than zero",
    ));
  }
  final List<WalletTransaction> sortedInputs =
      List.from(unspentInputsAvailable);
  sortedInputs.sort((a, b) => b.amount.compareTo(a.amount));
  List<ShelleyTransactionInput> results = [];
  Coin selectedAmount = 0;
  int coinsSelected = 0;
  for (final tx in sortedInputs) {
    if (tx.status != TransactionStatus.unspent) {
      logger.i("SHOULDN'T SEE TransactionStatus.unspent HERE: ${tx.txId}");
    }
    // int index = 0;
    for (int index = 0; index < tx.outputs.length; index++) {
      final output = tx.outputs[index];
      //Coin coinAmount = tx.currencyAmount(assetId: hardCodedUnit);
      final contains = ownedAddresses.contains(output.address);
      logger.i(
          "contains:$contains, tx=${tx.txId.substring(0, 20)} index[$index]=${output.amounts.first.quantity}");
      if (contains) {
        for (final txAmount in output.amounts) {
          if (txAmount.quantity > 0 && txAmount.unit == hardCodedUnit) {
            selectedAmount += txAmount.quantity;
            if (logSelection) {
              logger.i(
                  "selectedAmount += quantity: $selectedAmount += ${txAmount.quantity} -> tx: ${tx.txId} index: $index");
            }
            if (++coinsSelected > coinSelectionLimit) {
              return Err(CoinSelectionError(
                reason: CoinSelectionErrorEnum.inputsExhausted,
                message:
                    "coinsSelected ($coinsSelected) exceeds allowed coinSelectionLimit ($coinSelectionLimit)",
              ));
            }
            results.add(
                ShelleyTransactionInput(index: index, transactionId: tx.txId));
          }
        }
      }
      //index++;
    }
    if (selectedAmount >= amount) {
      break;
    }
  }
  if (selectedAmount < amount) {
    return Err(CoinSelectionError(
      reason: CoinSelectionErrorEnum.inputValueInsufficient,
      message: "insufficient funds",
    ));
  }
  return Ok(CoinSelection(inputs: results));
}