PHP WebShell

Текущая директория: /opt/BitGoJS/modules/utxo-lib/src/bitgo

Просмотр файла: Unspent.ts

import { TxOutput } from 'bitcoinjs-lib';
import { Network } from '..';
import { fromOutputScript, toOutputScript } from '../address';
import { UtxoTransactionBuilder } from './UtxoTransactionBuilder';
import { UtxoTransaction } from './UtxoTransaction';

/**
 * Public unspent data in BitGo-specific representation.
 */
export interface Unspent<TNumber extends number | bigint = number> {
  /**
   * Format: ${txid}:${vout}.
   * Use `parseOutputId(id)` to parse.
   */
  id: string;
  /**
   * The network-specific encoded address.
   * Use `toOutputScript(address, network)` to obtain scriptPubKey.
   */
  address: string;
  /**
   * The amount in satoshi.
   */
  value: TNumber;
}

export interface UnspentWithPrevTx<TNumber extends number | bigint = number> extends Unspent<TNumber> {
  prevTx: Buffer;
}

export function isUnspentWithPrevTx<TNumber extends number | bigint, TUnspent extends Unspent<TNumber>>(
  u: Unspent<TNumber>
): u is TUnspent & { prevTx: Buffer } {
  return Buffer.isBuffer((u as UnspentWithPrevTx<TNumber>).prevTx);
}

/**
 * @return TxOutput from Unspent
 */
export function toOutput<TNumber extends number | bigint>(u: Unspent<TNumber>, network: Network): TxOutput<TNumber> {
  return {
    script: toOutputScript(u.address, network),
    value: u.value,
  };
}

/**
 * @return Unspent from TxOutput
 */
export function fromOutput<TNumber extends number | bigint>(
  tx: UtxoTransaction<TNumber>,
  vout: number
): Unspent<TNumber> {
  const o = tx.outs[vout];
  if (!o) {
    throw new Error(`invalid vout`);
  }
  return {
    id: formatOutputId({ txid: tx.getId(), vout }),
    address: fromOutputScript(o.script, tx.network),
    value: o.value,
  };
}

export function fromOutputWithPrevTx<TNumber extends number | bigint>(
  tx: UtxoTransaction<TNumber>,
  vout: number
): UnspentWithPrevTx<TNumber> {
  return {
    ...fromOutput(tx, vout),
    prevTx: tx.toBuffer(),
  };
}

/**
 * @param outputId
 * @return TxOutPoint
 */
export function parseOutputId(outputId: string): TxOutPoint {
  const parts = outputId.split(':');
  if (parts.length !== 2) {
    throw new Error(`invalid outputId, must have format txid:vout`);
  }
  const [txid, voutStr] = parts;
  const vout = Number(voutStr);
  if (txid.length !== 64) {
    throw new Error(`invalid txid ${txid} ${txid.length}`);
  }
  if (Number.isNaN(vout) || vout < 0 || !Number.isSafeInteger(vout)) {
    throw new Error(`invalid vout: must be integer >= 0`);
  }
  return { txid, vout };
}

/**
 * @param txid
 * @param vout
 * @return outputId
 */
export function formatOutputId({ txid, vout }: TxOutPoint): string {
  return `${txid}:${vout}`;
}

export function getOutputIdForInput(i: { hash: Buffer; index: number }): TxOutPoint {
  return {
    txid: Buffer.from(i.hash).reverse().toString('hex'),
    vout: i.index,
  };
}

/**
 * Reference to output of an existing transaction
 */
export type TxOutPoint = {
  txid: string;
  vout: number;
};

/**
 * Output reference and script data.
 * Suitable for use for `txb.addInput()`
 */
export type PrevOutput<TNumber extends number | bigint = number> = TxOutPoint &
  TxOutput<TNumber> & {
    prevTx?: Buffer;
  };

/**
 * @return PrevOutput from Unspent
 */
export function toPrevOutput<TNumber extends number | bigint>(
  u: Unspent<TNumber>,
  network: Network
): PrevOutput<TNumber> {
  return {
    ...parseOutputId(u.id),
    ...toOutput(u, network),
  };
}

/**
 * @return PrevOutput with prevTx from Unspent
 */
export function toPrevOutputWithPrevTx<TNumber extends number | bigint>(
  u: Unspent<TNumber> & { prevTx?: unknown },
  network: Network
): PrevOutput<TNumber> {
  let prevTx;
  if (typeof u.prevTx === 'string') {
    prevTx = Buffer.from(u.prevTx, 'hex');
  } else if (Buffer.isBuffer(u.prevTx)) {
    prevTx = u.prevTx;
  } else if (u.prevTx !== undefined) {
    throw new Error(`Invalid prevTx type for unspent ${u.prevTx}`);
  }
  return {
    ...parseOutputId(u.id),
    ...toOutput(u, network),
    prevTx,
  };
}

/**
 * @param txb
 * @param u
 * @param sequence - sequenceId
 */
export function addToTransactionBuilder<TNumber extends number | bigint>(
  txb: UtxoTransactionBuilder<TNumber>,
  u: Unspent<TNumber>,
  sequence?: number
): void {
  const { txid, vout, script, value } = toPrevOutput(u, txb.network as Network);
  txb.addInput(txid, vout, sequence, script, value);
}

/**
 * Sum the values of the unspents.
 * Throws error if sum is not a safe integer value, or if unspent amount types do not match `amountType`
 * @param unspents - array of unspents to sum
 * @param amountType - expected value type of unspents
 * @return unspentSum - type matches amountType
 */
export function unspentSum<TNumber extends number | bigint>(
  unspents: { value: TNumber }[],
  amountType: 'number' | 'bigint' = 'number'
): TNumber {
  if (amountType === 'bigint') {
    return unspents.reduce((sum, u) => sum + (u.value as bigint), BigInt(0)) as TNumber;
  } else {
    const sum = unspents.reduce((sum, u) => sum + (u.value as number), Number(0));
    if (!Number.isSafeInteger(sum)) {
      throw new Error('unspent sum is not a safe integer number, consider using bigint');
    }
    return sum as TNumber;
  }
}

Выполнить команду


Для локальной разработки. Не используйте в интернете!