text: import { LegacyWallet } from './legacy-wallet';
  const bitcoin = require('bitcoinjs-lib');
  
  /**
   * Creates Segwit P2SH Bitcoin address
   * @param pubkey
   * @param network
   * @returns {String}
   */
  function pubkeyToP2shSegwitAddress(pubkey, network) {
    network = network || bitcoin.networks.bitcoin;
    const { address } = bitcoin.payments.p2sh({
      redeem: bitcoin.payments.p2wpkh({ pubkey, network }),
      network,
    });
    return address;
  }
  
  export class SegwitP2SHWallet extends LegacyWallet {
    static type = 'segwitP2SH';
    static typeReadable = 'SegWit (P2SH)';
  
    static witnessToAddress(witness) {
      try {
        const pubKey = Buffer.from(witness, 'hex');
        return pubkeyToP2shSegwitAddress(pubKey);
      } catch (_) {
        return false;
      }
    }
  
    /**
     * Converts script pub key to p2sh address if it can. Returns FALSE if it cant.
     *
     * @param scriptPubKey
     * @returns {boolean|string} Either p2sh address or false
     */
    static scriptPubKeyToAddress(scriptPubKey) {
      try {
        const scriptPubKey2 = Buffer.from(scriptPubKey, 'hex');
        return bitcoin.payments.p2sh({
          output: scriptPubKey2,
          network: bitcoin.networks.bitcoin,
        }).address;
      } catch (_) {
        return false;
      }
    }
  
    getAddress() {
      if (this._address) return this._address;
      let address;
      try {
        const keyPair = bitcoin.ECPair.fromWIF(this.secret);
        const pubKey = keyPair.publicKey;
        if (!keyPair.compressed) {
          console.warn('only compressed public keys are good for segwit');
          return false;
        }
        address = pubkeyToP2shSegwitAddress(pubKey);
      } catch (err) {
        return false;
      }
      this._address = address;
  
      return this._address;
    }
  
    /**
     *
     * @param utxos {Array.<{vout: Number, value: Number, txId: String, address: String, txhex: String, }>} List of spendable utxos
     * @param targets {Array.<{value: Number, address: String}>} Where coins are going. If theres only 1 target and that target has no value - this will send MAX to that address (respecting fee rate)
     * @param feeRate {Number} satoshi per byte
     * @param changeAddress {String} Excessive coins will go back to that address
     * @param sequence {Number} Used in RBF
     * @param skipSigning {boolean} Whether we should skip signing, use returned `psbt` in that case
     * @param masterFingerprint {number} Decimal number of wallet's master fingerprint
     * @returns {{outputs: Array, tx: Transaction, inputs: Array, fee: Number, psbt: Psbt}}
     */
    createTransaction(utxos, targets, feeRate, changeAddress, sequence, skipSigning = false, masterFingerprint) {
      if (targets.length === 0) throw new Error('No destination provided');
      const { inputs, outputs, fee } = this.coinselect(utxos, targets, feeRate, changeAddress);
      sequence = sequence || 0xffffffff; // disable RBF by default
      const psbt = new bitcoin.Psbt();
      let c = 0;
      const values = {};
      let keyPair;
  
      inputs.forEach(input => {
        if (!skipSigning) {
          // skiping signing related stuff
          keyPair = bitcoin.ECPair.fromWIF(this.secret); // secret is WIF
        }
        values[c] = input.value;
        c++;
  
        const pubkey = keyPair.publicKey;
        const p2wpkh = bitcoin.payments.p2wpkh({ pubkey });
        const p2sh = bitcoin.payments.p2sh({ redeem: p2wpkh });
  
        psbt.addInput({
          hash: input.txid,
          index: input.vout,
          sequence,
          witnessUtxo: {
            script: p2sh.output,
            value: input.value,
          },
          redeemScript: p2wpkh.output,
        });
      });
  
      outputs.forEach(output => {
        // if output has no address - this is change output
        if (!output.address) {
          output.address = changeAddress;
        }
  
        const outputData = {
          address: output.address,
          value: output.value,
        };
  
        psbt.addOutput(outputData);
      });
  
      if (!skipSigning) {
        // skiping signing related stuff
        for (let cc = 0; cc < c; cc++) {
          psbt.signInput(cc, keyPair);
        }
      }
  
      let tx;
      if (!skipSigning) {
        tx = psbt.finalizeAllInputs().extractTransaction();
      }
      return { tx, inputs, outputs, fee, psbt };
    }
  
    allowSendMax() {
      return true;
    }
  }
  