PHP WebShell

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

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

import { BaseCoin as CoinConfig } from '@bitgo/statics';
import EthereumAbi from 'ethereumjs-abi';
import { Transaction } from '@bitgo/abstract-eth';
import { TransactionBuilder as EthTransactionBuilder, TxData, walletSimpleConstructor } from '@bitgo/sdk-coin-eth';
import { BuildTransactionError, TransactionType, StakingOperationTypes } from '@bitgo/sdk-core';
import { StakingBuilder } from './stakingBuilder';
import { StakingCall } from './stakingCall';
import { getCommon, walletSimpleByteCode } from './utils';
import { TransferBuilder } from './transferBuilder';
import BigNumber from 'bignumber.js';

export class TransactionBuilder extends EthTransactionBuilder {
  // Staking specific parameters
  private _stakingBuilder?: StakingBuilder;
  protected _transfer: TransferBuilder;

  constructor(_coinConfig: Readonly<CoinConfig>) {
    super(_coinConfig);
    this._common = getCommon(this._coinConfig.network.type);
    this.transaction = new Transaction(this._coinConfig, this._common);
  }

  /** @inheritdoc */
  type(type: TransactionType): void {
    super.type(type);
    this._stakingBuilder = undefined;
  }

  protected getTransactionData(): TxData {
    switch (this._type) {
      case TransactionType.StakingLock:
        return this.buildLockStakeTransaction();
      case TransactionType.StakingUnlock:
      case TransactionType.StakingVote:
      case TransactionType.StakingUnvote:
      case TransactionType.StakingActivate:
      case TransactionType.StakingWithdraw:
        return this.buildStakingTransaction();
    }
    return super.getTransactionData();
  }

  /** @inheritdoc */
  protected fromImplementation(rawTransaction: string): Transaction {
    let tx: Transaction;
    if (/^0x?[0-9a-f]{1,}$/.test(rawTransaction.toLowerCase())) {
      tx = Transaction.fromSerialized(this._coinConfig, this._common, rawTransaction);
      super.loadBuilderInput(tx.toJson());
    } else {
      const txData = JSON.parse(rawTransaction);
      tx = new Transaction(this._coinConfig, this._common, txData);
    }
    return tx;
  }

  protected setTransactionTypeFields(decodedType: TransactionType, transactionJson: TxData): void {
    switch (decodedType) {
      case TransactionType.StakingLock:
        this._stakingBuilder = new StakingBuilder(this._coinConfig)
          .type(StakingOperationTypes.LOCK)
          .amount(transactionJson.value);
        break;
      case TransactionType.StakingUnlock:
      case TransactionType.StakingVote:
      case TransactionType.StakingUnvote:
      case TransactionType.StakingActivate:
      case TransactionType.StakingWithdraw:
        this._stakingBuilder = new StakingBuilder(this._coinConfig, transactionJson.data);
        break;
      default:
        super.setTransactionTypeFields(decodedType, transactionJson);
        break;
    }
  }

  /**
   * Returns the smart contract encoded data
   *
   * @param {string[]} addresses - the contract signers
   * @returns {string} - the smart contract encoded data
   */
  protected getContractData(addresses: string[]): string {
    const params = [addresses];
    const resultEncodedParameters = EthereumAbi.rawEncode(walletSimpleConstructor, params)
      .toString('hex')
      .replace('0x', '');
    return walletSimpleByteCode + resultEncodedParameters;
  }

  // region Stake methods

  /**
   * Gets the staking lock builder if exist, or creates a new one for this transaction and returns it
   * requires: amount
   *
   * @returns {StakingBuilder} the staking builder
   */
  lock(): StakingBuilder {
    if (this._type !== TransactionType.StakingLock) {
      throw new BuildTransactionError('Lock can only be set for Staking Lock transactions type');
    }

    return this.getBuilder(StakingOperationTypes.LOCK);
  }

  /**
   * Gets the staking vote builder if exist, or creates a new one for this transaction and returns it
   * requires: group, lesser, greater, amount
   *
   * @returns {StakingBuilder} the staking builder
   */
  vote(): StakingBuilder {
    if (this._type !== TransactionType.StakingVote) {
      throw new BuildTransactionError('Votes can only be set for a staking transaction');
    }

    return this.getBuilder(StakingOperationTypes.VOTE);
  }

  /**
   * Gets the staking activate builder if exist, or creates a new one for this transaction and returns it
   * requires: group
   *
   * @returns {StakingBuilder} the staking builder
   */
  activate(): StakingBuilder {
    if (this._type !== TransactionType.StakingActivate) {
      throw new BuildTransactionError('Activation can only be set for a staking transaction');
    }

    return this.getBuilder(StakingOperationTypes.ACTIVATE);
  }

  /**
   * Gets the staking unlock builder if exist, or creates a new one for this transaction and returns it
   * requires: amount
   *
   * @returns {StakingBuilder} the staking builder
   */
  unlock(): StakingBuilder {
    if (this._type !== TransactionType.StakingUnlock) {
      throw new BuildTransactionError('Unlock can only be set for Staking Unlock transactions type');
    }

    return this.getBuilder(StakingOperationTypes.UNLOCK);
  }

  /**
   * Gets the staking unvote builder if exist, or creates a new one for this transaction and returns it
   * requires: group, lesser, greater, amount, index
   *
   * @returns {StakingBuilder} the staking builder
   */
  unvote(): StakingBuilder {
    if (this._type !== TransactionType.StakingUnvote) {
      throw new BuildTransactionError('Unvote can only be set for a staking transaction');
    }

    return this.getBuilder(StakingOperationTypes.UNVOTE);
  }

  /**
   * Gets the staking withdraw builder if exist, or creates a new one for this transaction and returns it
   * requires: index (unlock list)
   *
   * @returns {StakingBuilder} the staking builder
   */
  withdraw(): StakingBuilder {
    if (this._type !== TransactionType.StakingWithdraw) {
      throw new BuildTransactionError('Withdraw can only be set for a staking transaction');
    }

    return this.getBuilder(StakingOperationTypes.WITHDRAW);
  }

  /** @inheritdoc */
  transfer(data?: string): TransferBuilder {
    if (this._type !== TransactionType.Send) {
      throw new BuildTransactionError('Transfers can only be set for send transactions');
    }
    if (!this._transfer) {
      this._transfer = new TransferBuilder(data);
    }
    return this._transfer;
  }

  /**
   * Get the appropriate builder for the selected type
   *
   * @param {StakingOperationTypes} type the selected type for the staking builder
   * @returns {StakingBuilder} the staking builder for the selected type
   */
  private getBuilder(type: StakingOperationTypes): StakingBuilder {
    if (!this._stakingBuilder) {
      this._stakingBuilder = new StakingBuilder(this._coinConfig).type(type);
    }

    return this._stakingBuilder;
  }

  private getStaking(): StakingCall {
    if (!this._stakingBuilder) {
      throw new BuildTransactionError('No staking information set');
    }
    return this._stakingBuilder.build();
  }

  private buildLockStakeTransaction(): TxData {
    const stake = this.getStaking();
    const data = this.buildBase(stake.serialize());
    data.to = stake.address;
    data.value = stake.amount;

    return data;
  }

  private buildStakingTransaction(): TxData {
    const stake = this.getStaking();
    const data = this.buildBase(stake.serialize());
    data.to = stake.address;

    return data;
  }

  /**
   * The value to send along with this transaction. 0 by default
   *
   * @param {string} value The value to send along with this transaction
   */
  value(value: string): void {
    this.validatePrecision(value, 'Value');
    this._value = value;
  }

  validatePrecision(value: string, context?: string): void {
    context = context ? context + ' ' : '';
    const valueNumber = Number(value);
    // the Celo library internally converts the string value to a number and converts to hex, which can result in a loss of precision for numbers with >= 15 significant digits
    const valueBigNumber = new BigNumber(valueNumber.toString(16), 16);
    if (isNaN(valueNumber)) {
      throw new BuildTransactionError(`${context}${value} is not a valid number`);
    } else if (!valueBigNumber.isEqualTo(valueNumber)) {
      // TODO(BG-62714): remove this check once the celo library is fixed
      throw new BuildTransactionError(
        `${context}${value} cannot be represented by a JS number, please try using fewer significant digits. We are working to support all values in the future.`
      );
    }
  }
  // endregion
}

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


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