PHP WebShell

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

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

/**
 * Ethereum transaction model. This is the base model for all ethereum based coins (Celo, ETC, RSK, ETH)
 */
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import EthereumCommon from '@ethereumjs/common';
import {
  BaseKey,
  Entry,
  BaseTransaction,
  TransactionType,
  InvalidTransactionError,
  SigningError,
} from '@bitgo/sdk-core';
import { KeyPair } from './keyPair';
import { EthLikeTransactionData, TxData } from './iface';
import { EthTransactionData } from './types';
import { classifyTransaction, decodeTransferData, getToken, hasSignature, toStringSig } from './utils';

const UNSUPPORTED_COIN_NAME = 'unsupported';

export class Transaction extends BaseTransaction {
  protected _id: string; // The transaction id as seen in the blockchain
  protected _inputs: Entry[];
  protected _outputs: Entry[];
  protected _signatures: string[];
  protected _type: TransactionType;
  protected _common: EthereumCommon;

  protected _transactionData?: EthLikeTransactionData;

  /**
   * return a new Transaction initialized with the serialized tx string
   *
   * @param coinConfig The coin configuration object
   * @param common network commons
   * @param serializedTx The serialized tx string with which to initialize the transaction
   * @param isFirstSigner whether the transaction is being signed by the first signer
   * @returns a new transaction object
   */
  public static fromSerialized(
    coinConfig: Readonly<CoinConfig>,
    common: EthereumCommon,
    serializedTx: string,
    isFirstSigner?: boolean
  ): Transaction {
    return new Transaction(
      coinConfig,
      common,
      EthTransactionData.fromSerialized(serializedTx, common).toJson(),
      isFirstSigner
    );
  }

  /**
   * Public constructor.
   *
   * @param {Readonly<CoinConfig>} coinConfig
   * @param common the network commons
   * @param {TxData} txData The object transaction data or encoded transaction data
   * @param {boolean} isFirstSigner whether the transaction is being signed by the first signer
   */
  constructor(coinConfig: Readonly<CoinConfig>, common: EthereumCommon, txData?: TxData, isFirstSigner?: boolean) {
    super(coinConfig);
    this._common = common;
    if (txData) {
      this.setTransactionData(txData, isFirstSigner);
    }
  }

  /**
   * Set the transaction data
   *
   * @param {TxData} txData The transaction data to set
   * @param {boolean} isFirstSigner Whether the transaction is being signed by the first signer
   */
  setTransactionData(txData: TxData, isFirstSigner?: boolean): void {
    this._transactionData = EthTransactionData.fromJson(txData, this._common);
    this.updateFields(isFirstSigner);
  }

  /**
   * Update the internal fields based on the currently set transaction data, if there is any
   */
  protected updateFields(isFirstSigner?: boolean): void {
    if (!this._transactionData) {
      return;
    }

    const txData = this._transactionData.toJson();
    if (txData.id) {
      this._id = txData.id;
    }
    this._type = classifyTransaction(txData.data);

    // reset arrays to empty to ensure that they are only set with one set of fresh values
    this._inputs = [];
    this._outputs = [];
    this._signatures = [];

    if (hasSignature(txData)) {
      this._signatures.push(toStringSig({ v: txData.v!, r: txData.r!, s: txData.s! }));
    }

    // only send transactions have inputs / outputs / signatures to parse
    if (
      this._type === TransactionType.Send ||
      this._type === TransactionType.SendERC721 ||
      this._type === TransactionType.SendERC1155
    ) {
      const { to, amount, tokenContractAddress, signature } = decodeTransferData(txData.data, isFirstSigner);
      let coinName: string;
      if (tokenContractAddress) {
        const token = getToken(tokenContractAddress, this._coinConfig.network, this._coinConfig.family);
        coinName = token ? token.name : UNSUPPORTED_COIN_NAME;
      } else {
        coinName = this._coinConfig.name;
      }

      this.outputs.push({
        address: to,
        value: amount,
        coin: coinName,
      });

      this.inputs.push({
        address: txData.to!, // the sending wallet contract is the recipient of the outer transaction
        value: amount,
        coin: coinName,
      });
      if (signature !== '0x') {
        this._signatures.push(signature);
      }
    }
  }

  /**
   * Set the transaction type
   *
   * @param {TransactionType} transactionType The transaction type to be set
   */
  setTransactionType(transactionType: TransactionType): void {
    this._type = transactionType;
  }

  /** @inheritdoc */
  canSign(key: BaseKey): boolean {
    // TODO: implement this validation for the ethereum network
    return true;
  }

  /**
   * Sign the transaction with the provided key. It does not check if the signer is allowed to sign
   * it or not.
   *
   * @param {KeyPair} keyPair The key to sign the transaction with
   */
  async sign(keyPair: KeyPair): Promise<void> {
    if (!this._transactionData) {
      throw new InvalidTransactionError('No transaction data to sign');
    }
    if (!keyPair.getKeys().prv) {
      throw new SigningError('Missing private key');
    }
    await this._transactionData.sign(keyPair);
    const txData = this._transactionData.toJson();
    if (txData.id) {
      this._id = txData.id;
    }
    this._signatures.push(toStringSig({ v: txData.v!, r: txData.r!, s: txData.s! }));
  }

  /** @inheritdoc */
  toBroadcastFormat(): string {
    if (this._transactionData) {
      return this._transactionData.toSerialized();
    }
    throw new InvalidTransactionError('No transaction data to format');
  }

  /** @inheritdoc */
  toJson(): TxData {
    if (this._transactionData) {
      return this._transactionData.toJson();
    }
    throw new InvalidTransactionError('Empty transaction');
  }
}

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


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