PHP WebShell

Текущая директория: /opt/BitGoJS/modules/sdk-core/src/account-lib/baseCoin

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

import BigNumber from 'bignumber.js';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { BaseAddress, BaseKey, PublicKey, ValidityWindow } from './iface';
import { BaseTransaction } from './baseTransaction';
import { SigningError } from './errors';

/**
 * Generic transaction builder to be extended with coin specific logic.
 * Provide a set of default steps (i.e. from, sign, build) and enforces mandatory validations.
 */
export abstract class BaseTransactionBuilder {
  protected _coinConfig: Readonly<CoinConfig>;
  /**
   * Base constructor.
   *
   * @param _coinConfig BaseCoin from statics library
   */
  protected constructor(_coinConfig: Readonly<CoinConfig>) {
    this._coinConfig = _coinConfig;
  }

  /**
   * Parse a transaction based on existing data. The input format is determined by the coin
   * extending this class. Some examples are hex, base64, or JSON.
   *
   * @param rawTransaction A raw transaction to be parsed
   * @param isFirstSigner Whether the transaction is being signed by the first signer
   */
  from(rawTransaction: any, isFirstSigner?: boolean): void {
    this.validateRawTransaction(rawTransaction);
    this.transaction = this.fromImplementation(rawTransaction, isFirstSigner);
  }

  /**
   * Coin specific implementation of {@code from}.
   *
   * @see {@link from}
   * @returns the parsed coin specific transaction object
   */
  protected abstract fromImplementation(rawTransaction: any, isFirstSigner?: boolean): BaseTransaction;

  /**
   * Validate keys and sign the transaction.
   *
   * @param key One of the keys associated with this transaction
   */
  sign(key: BaseKey): void {
    this.validateKey(key);
    if (!this.transaction.canSign(key)) {
      throw new SigningError('Private key cannot sign the transaction');
    }

    this.transaction = this.signImplementation(key);
  }

  /**
   * Adds a signature to the transaction.
   *
   * @param publicKey public key that produced the signature
   * @param signature raw signature as a hex encoded Buffer
   */
  addSignature(publicKey: PublicKey, signature: Buffer): void {
    throw new SigningError(`${this.coinName()} does not support adding signatures directly.`);
  }

  /**
   * Coin specific implementation of {@code sign}.
   *
   * @see {@link sign}
   * @returns coin specific transaction with signature data
   */
  protected abstract signImplementation(key: BaseKey): BaseTransaction;

  /**
   * Finalize the transaction by performing any extra step like calculating hashes, verifying
   * integrity, or adding default values.
   *
   * @returns valid coin specific transaction (signed or unsigned)
   */
  async build(): Promise<BaseTransaction> {
    this.validateTransaction(this.transaction);
    return this.buildImplementation();
  }

  /**
   * Coin specific implementation of {@code build}.
   *
   * @see {@link build}
   * @returns valid coin specific transaction (signed or unsigned)
   */
  protected abstract buildImplementation(): Promise<BaseTransaction>;

  /**
   * Check the private key is present and is valid in the blockchain context, throw otherwise.
   *
   * @param {BaseKey} key Private key to validate
   */
  abstract validateKey(key: BaseKey): void;

  /**
   * Check the address provided is valid in the blockchain context, throw otherwise.
   *
   * @param address Address data to be validated
   * @param addressFormat The format the address should be in if more than one is supported
   */
  abstract validateAddress(address: BaseAddress, addressFormat?: string): void;

  /**
   * Check the amount provided is valid in the blockchain context, throw otherwise.
   *
   * @param {BigNumber} value Transaction amount
   */
  abstract validateValue(value: BigNumber): void;

  /**
   * Check the raw transaction has a valid format in the blockchain context, throw otherwise.
   *
   * @param rawTransaction Transaction in any format
   */
  abstract validateRawTransaction(rawTransaction: any): void;

  /**
   * Check the transaction mandatory fields per transaction type and ensures it is valid, throw
   * otherwise.
   *
   * @param {BaseTransaction} transaction
   */
  abstract validateTransaction(transaction?: BaseTransaction): void;

  /**
   * Get the underlying coin full name as specified in the statics library.
   */
  displayName(): string {
    return this._coinConfig.fullName;
  }

  /**
   * Get the underlying coin full name as specified in the statics library.
   */
  coinName(): string {
    return this._coinConfig.name;
  }

  /**
   * Verified validity windows params if them exist and return a valid validity windows.
   * Unit param must be specified
   * If params are not consistent, default params will be return based on firstValid and minDuration
   * @param {ValidityWindow} params validity windows parameters to validate.
   * @param {String} params.unit Parameter that could be 'blockheight' or 'timestamp'
   * @param {Number} [params.minDuration] Optional - Minimum duration of the window
   * @param {Number} [params.maxDuration] Optional - Maximum duration of the window
   * @param {Number} [params.firstValid] Optional - First valid value
   * @param {Number} [params.lastValid] Optional - Last valid value
   * @returns {ValidityWindow} verified validity windows or default values
   */
  getValidityWindow(params: ValidityWindow): ValidityWindow {
    if (!params.unit || (params.unit !== 'timestamp' && params.unit !== 'blockheight')) {
      throw new Error('Unit parameter must be specified as blockheight or timestamp');
    }
    const unit = params.unit;
    let defaultMinDuration: number;
    let defaultMaxDuration: number;
    let defaultFirstValid: number;
    let defaultLastValid: number;

    /* Set Default Params
      minimum duration is set as 1 hr (3600000 msec) if unit is timestamp or 20 blocks if it is blockheight
      maximum duration is set as 1 year (31536000000 msec) if unit is timestamp or 1000000 blocks if it is blockheight.
     */
    if (unit === 'timestamp') {
      defaultMinDuration = 0;
      defaultMaxDuration = 31536000000;
      defaultFirstValid = Date.now();
      defaultLastValid = defaultFirstValid + defaultMaxDuration;
    } else {
      defaultMinDuration = 0;
      defaultMaxDuration = 1000000;
      defaultFirstValid = 0;
      defaultLastValid = defaultFirstValid + defaultMaxDuration;
    }

    // If any params exist, they will be used, otherwise it will be used default params.
    let firstValid: number = params.firstValid || defaultFirstValid;
    let lastValid: number = params.lastValid || defaultLastValid;
    let minDuration: number = params.minDuration || defaultMinDuration;
    let maxDuration: number = params.maxDuration || defaultMaxDuration;

    /* Validate Params:
      minDuration < maxDuration
      firstValid < lastValid
      firstValid + minDuration <= lastValid <= firstValid + maxDuration
     */
    if (minDuration >= maxDuration) {
      throw new Error(`Expected maxDuration (${maxDuration}) to be grather than minDuration (${minDuration})`);
    }
    firstValid = firstValid >= 0 ? firstValid : defaultFirstValid;
    minDuration = minDuration >= 0 ? minDuration : defaultMinDuration;
    maxDuration = maxDuration > minDuration ? maxDuration : defaultMaxDuration;
    lastValid =
      lastValid >= firstValid + minDuration && lastValid <= firstValid + maxDuration
        ? lastValid
        : firstValid + maxDuration;

    return {
      firstValid,
      lastValid,
      minDuration,
      maxDuration,
      unit,
    };
  }

  /**
   * Get the transaction being built.
   */
  protected abstract get transaction(): BaseTransaction;

  /**
   * Set the transaction being built.
   */
  protected abstract set transaction(transaction: BaseTransaction);
}

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


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