<commit_before>import * as _ from 'lodash';
import { Key } from '../../derivation';

export class BTCTxProvider {
  lib = require('bitcore-lib');

  selectCoins(
    recipients: Array<{ amount: number }>,
    utxos: Array<{
      value: number;
      mintHeight: number;
      txid?: string;
      mintTxid?: string;
      mintIndex?: number;
    }>,
    fee: number
  ) {
    utxos = utxos.sort(function(a, b) {
      return a.mintHeight - b.mintHeight;
    });

    let index = 0;
    let utxoSum = 0;
    let recepientSum = recipients.reduce(
      (sum, cur) => sum + Number(cur.amount),
      fee
    );
    while (utxoSum < recepientSum) {
      const utxo = utxos[index];
      utxoSum += Number(utxo.value);
      index += 1;
    }
    const filteredUtxos = utxos.slice(0, index);
    return filteredUtxos;
  }

  create({ recipients, utxos = [], change, wallet, fee = 20000 }) {
    change = change || (wallet.deriveAddress(wallet.addressIndex, true));
    const filteredUtxos = this.selectCoins(recipients, utxos, fee);
    const btcUtxos = filteredUtxos.map(utxo => {
      const btcUtxo = Object.assign({}, utxo, {
        amount: utxo.value / 1e8,
        txid: utxo.mintTxid,
        outputIndex: utxo.mintIndex
      });
      return new this.lib.Transaction.UnspentOutput(btcUtxo);
    });
    console.log(btcUtxos);
    let tx = new this.lib.Transaction().from(btcUtxos).fee(Number(fee));
    if (change) {
      tx.change(change);
    }
    for (const recipient of recipients) {
      tx.to(recipient.address, recipient.amount);
    }
    return tx.uncheckedSerialize();
  }

  getSignature(params: { tx: string; keys: Array<Key>}) {
    throw new Error('No implemented for UTXO coins');
  }

  applySignature(params: { tx: string; keys: Array<Key>}) {
    throw new Error('No implemented for UTXO coins');
  }

  getHash(params: { tx: string}) {
    throw new Error('No implemented for UTXO coins');
  }

  sign(params: { tx: string; keys: Array<Key>; utxos: any[] }) {
    const { tx, keys } = params;
    let utxos = params.utxos || [];
    let inputAddresses = this.getSigningAddresses({ tx, utxos });
    let bitcoreTx = new this.lib.Transaction(tx);
    let applicableUtxos = this.getRelatedUtxos({
      outputs: bitcoreTx.inputs,
      utxos
    });
    const outputs = this.getOutputsFromTx({ tx: bitcoreTx });
    let newTx = new this.lib.Transaction().from(applicableUtxos).to(outputs);
    const privKeys = _.uniq(keys.map(key => key.privKey.toString()));
    const signedTx = newTx.sign(privKeys).toString();
    return signedTx;
  }

  getRelatedUtxos({ outputs, utxos }) {
    let txids = outputs.map(output => output.toObject().prevTxId);
    let applicableUtxos = utxos.filter(utxo => txids.includes(utxo.txid));
    return applicableUtxos.map(utxo => {
      const btcUtxo = Object.assign({}, utxo, {
        amount: utxo.value / Math.pow(10, 8)
      });
      return new this.lib.Transaction.UnspentOutput(btcUtxo);
    });
  }

  getOutputsFromTx({ tx }) {
    return tx.outputs.map(({ script, satoshis }) => {
      let address = script;
      return { address, satoshis };
    });
  }

  getSigningAddresses({ tx, utxos }): string[] {
    let bitcoreTx = new this.lib.Transaction(tx);<commit_msg>getting proper utxos to sign with<commit_after>import * as _ from 'lodash';
import { Key } from '../../derivation';

export class BTCTxProvider {
  lib = require('bitcore-lib');

  selectCoins(
    recipients: Array<{ amount: number }>,
    utxos: Array<{
      value: number;
      mintHeight: number;
      txid?: string;
      mintTxid?: string;
      mintIndex?: number;
    }>,
    fee: number
  ) {
    utxos = utxos.sort(function(a, b) {
      return a.mintHeight - b.mintHeight;
    });

    let index = 0;
    let utxoSum = 0;
    let recepientSum = recipients.reduce(
      (sum, cur) => sum + Number(cur.amount),
      fee
    );
    while (utxoSum < recepientSum) {
      const utxo = utxos[index];
      utxoSum += Number(utxo.value);
      index += 1;
    }
    const filteredUtxos = utxos.slice(0, index);
    return filteredUtxos;
  }

  create({ recipients, utxos = [], change, wallet, fee = 20000 }) {
    change = change || (wallet.deriveAddress(wallet.addressIndex, true));
    const filteredUtxos = this.selectCoins(recipients, utxos, fee);
    const btcUtxos = filteredUtxos.map(utxo => {
      const btcUtxo = Object.assign({}, utxo, {
        amount: utxo.value / 1e8,
        txid: utxo.mintTxid,
        outputIndex: utxo.mintIndex
      });
      return new this.lib.Transaction.UnspentOutput(btcUtxo);
    });
    let tx = new this.lib.Transaction().from(btcUtxos).fee(Number(fee));
    if (change) {
      tx.change(change);
    }
    for (const recipient of recipients) {
      tx.to(recipient.address, recipient.amount);
    }
    return tx.uncheckedSerialize();
  }

  getSignature(params: { tx: string; keys: Array<Key>}) {
    throw new Error('No implemented for UTXO coins');
  }

  applySignature(params: { tx: string; keys: Array<Key>}) {
    throw new Error('No implemented for UTXO coins');
  }

  getHash(params: { tx: string}) {
    throw new Error('No implemented for UTXO coins');
  }

  sign(params: { tx: string; keys: Array<Key>; utxos: any[] }) {
    const { tx, keys } = params;
    let utxos = params.utxos || [];
    let inputAddresses = this.getSigningAddresses({ tx, utxos });
    let bitcoreTx = new this.lib.Transaction(tx);
    let applicableUtxos = this.getRelatedUtxos({
      outputs: bitcoreTx.inputs,
      utxos
    });
    const outputs = this.getOutputsFromTx({ tx: bitcoreTx });
    let newTx = new this.lib.Transaction().from(applicableUtxos).to(outputs);
    const privKeys = _.uniq(keys.map(key => key.privKey.toString()));
    const signedTx = newTx.sign(privKeys).toString();
    return signedTx;
  }

  getRelatedUtxos({ outputs, utxos }) {
    let txids = outputs.map(output => output.toObject().prevTxId);
    let applicableUtxos = utxos.filter(utxo => txids.includes(utxo.txid || utxo.mintTxid));
    return applicableUtxos.map(utxo => {
      const btcUtxo = Object.assign({}, utxo, {
        amount: utxo.value / Math.pow(10, 8),
        txid: utxo.mintTxid,
        outputIndex: utxo.mintIndex
      });
      return new this.lib.Transaction.UnspentOutput(btcUtxo);
    });
  }

  getOutputsFromTx({ tx }) {
    return tx.outputs.map(({ script, satoshis }) => {
      let address = script;
      return { address, satoshis };
    });
  }

  getSigningAddresses({ tx, utxos }): string[] {
    let bitcoreTx = new this.lib.Transaction(tx);
{'fraction_non_alphanumeric': 0.1433587786259542, 'fraction_numerical': 0.004274809160305344, 'mean_word_length': 2.9157202630005976, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4438551', 'n_tokens_mistral': 2310, 'n_tokens_neox': 2262, 'n_words': 494}