PHP WebShell

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

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

import BigNumber from 'bignumber.js';
import algosdk from 'algosdk';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { TransactionType, InvalidTransactionError } from '@bitgo/sdk-core';
import { TransactionBuilder } from './transactionBuilder';
import { Transaction } from './transaction';
import { KeyRegTxnSchema } from './txnSchema';
import Utils from './utils';

export class KeyRegistrationBuilder extends TransactionBuilder {
  protected _voteKey: string;
  protected _selectionKey: string;
  protected _voteFirst: number;
  protected _voteLast: number;
  protected _voteKeyDilution: number;
  protected _nonParticipation: boolean;
  protected _stateProofKey: string;

  constructor(coinConfig: Readonly<CoinConfig>) {
    super(coinConfig);
  }

  /**
   * Sets the vote key
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * @param {string} key The root participation public key. See Generate a Participation Key to learn more.
   * https://developer.algorand.org/docs/reference/transactions/#key-registration-transaction
   */
  voteKey(key: string): KeyRegistrationBuilder {
    this._voteKey = key;
    return this;
  }

  /**
   * Sets the selection key
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * @param {string} key The VRF public key for the account.
   * https://developer.algorand.org/docs/reference/transactions/#key-registration-transaction
   */
  selectionKey(key: string): KeyRegistrationBuilder {
    this._selectionKey = key;
    return this;
  }

  /**
   * Sets the stateProof key
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * @param {string} key The stateproof key. See consensus for more information.
   * https://developer.algorand.org/docs/get-details/algorand_consensus/?from_query=state#state-proof-keys
   */
  stateProofKey(key: string): KeyRegistrationBuilder {
    Utils.validateBase64(key);
    this._stateProofKey = key;
    return this;
  }

  /**
   *Sets the vote first round
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * @param {number} round The first round that the participation key is valid. Not to be confused with the FirstValid round of the keyreg transaction.
   * https://developer.algorand.org/docs/reference/transactions/#key-registration-transaction
   */
  voteFirst(round: number): KeyRegistrationBuilder {
    this.validateValue(new BigNumber(round));
    this._voteFirst = round;

    return this;
  }

  /**
   * Sets the vote last round
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * A recommended range is 3,000,000 rounds.
   *
   * @param {number} round No theoretical limit.
   * https://developer.algorand.org/docs/run-a-node/participate/generate_keys/
   */
  voteLast(round: number): KeyRegistrationBuilder {
    this.validateValue(new BigNumber(round));
    this._voteLast = round;

    return this;
  }

  /**
   * Sets the vote key dilution
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * Defaults to 10,000
   *
   * @param {number} size [10000]. To reduce the size of the participation key, set the key dilution value to roughly the square root of the range that the partkey is valid for.
   * https://developer.algorand.org/docs/run-a-node/participate/generate_keys/#generate-the-participation-key-with-goal
   * @param size
   */
  voteKeyDilution(size = 10000): KeyRegistrationBuilder {
    this.validateValue(new BigNumber(size));
    this._voteKeyDilution = size;

    return this;
  }

  /**
   * Sets the non participation flag
   *
   * @returns {KeyRegistrationBuilder} This Key Registration builder.
   *
   * @param {boolean} nonParticipation All new Algorand accounts are participating by default.
   * This means that they earn rewards. Mark an account nonparticipating by setting this value to true and this account
   * will no longer earn rewards NEVER.
   * https://developer.algorand.org/docs/reference/transactions/#key-registration-transaction
   */
  nonParticipation(nonParticipation: boolean): KeyRegistrationBuilder {
    this._nonParticipation = nonParticipation;

    return this;
  }

  protected buildAlgoTxn(): algosdk.Transaction {
    return this.isOfflineKeyRegAccountLibTransaction()
      ? this.buildOfflineKeyRegTransaction()
      : this.isNonParticipationKeyRegAccountLibTransaction()
      ? this.buildNonParticipationKeyRegTransaction()
      : this.buildOnlineKeyRegTransaction();
  }

  private buildOfflineKeyRegTransaction(): algosdk.Transaction {
    return algosdk.makeKeyRegistrationTxnWithSuggestedParams(
      this._sender,
      this._note,
      undefined, // voteKey param
      undefined, // selectionKey param
      undefined, // voteFirst param
      undefined, // voteLast param
      undefined, // voteKeyDilution param
      this.suggestedParams
    );
  }

  private buildOnlineKeyRegTransaction(): algosdk.Transaction {
    return algosdk.makeKeyRegistrationTxnWithSuggestedParams(
      this._sender,
      this._note,
      this._voteKey,
      this._selectionKey,
      this._voteFirst,
      this._voteLast,
      this._voteKeyDilution,
      this.suggestedParams,
      undefined, // reKeyTo param
      undefined, // nonParticipation param
      this._stateProofKey
    );
  }

  private buildNonParticipationKeyRegTransaction(): algosdk.Transaction {
    return algosdk.makeKeyRegistrationTxnWithSuggestedParams(
      this._sender,
      this._note,
      undefined, // voteKey param
      undefined, // selectionKey param
      undefined, // voteFirst param
      undefined, // voteLast param
      undefined, // voteKeyDilution param
      this.suggestedParams,
      this._reKeyTo,
      true // nonParticipation param
    );
  }

  protected get transactionType(): TransactionType {
    return TransactionType.WalletInitialization;
  }

  /** @inheritdoc */
  protected fromImplementation(rawTransaction: Uint8Array | string): Transaction {
    const tx = super.fromImplementation(rawTransaction);
    const algoTxn = tx.getAlgoTransaction();

    if (algoTxn) {
      if (this.isNonParticipationKeyRegAlgoSDKTransaction(algoTxn)) {
        this.nonParticipation(!!algoTxn.nonParticipation);
      } else if (this.isOnlineKeyRegAlgoSDKTransaction(algoTxn)) {
        this.voteKey(algoTxn.voteKey.toString('base64'));
        this.selectionKey(algoTxn.selectionKey.toString('base64'));
        this.voteFirst(algoTxn.voteFirst);
        this.voteLast(algoTxn.voteLast);
        this.voteKeyDilution(algoTxn.voteKeyDilution);
        if (algoTxn.stateProofKey) {
          this.stateProofKey(algoTxn.stateProofKey.toString('base64'));
        }
      }
    }
    return tx;
  }

  /** @inheritdoc */
  validateRawTransaction(rawTransaction: Uint8Array | string): void {
    const decodeTxn = Utils.decodeAlgoTxn(rawTransaction);
    const algoTxn = decodeTxn.txn;
    if (algoTxn.type !== algosdk.TransactionType.keyreg) {
      throw new InvalidTransactionError(
        `Invalid Transaction Type: ${algoTxn.type}. Expected ${algosdk.TransactionType.keyreg}`
      );
    }

    if (this.isOnlineKeyRegAlgoSDKTransaction(algoTxn)) {
      this.validateFields(
        algoTxn.voteKey.toString('base64'),
        algoTxn.selectionKey.toString('base64'),
        algoTxn.voteFirst,
        algoTxn.voteLast,
        algoTxn.voteKeyDilution,
        algoTxn.stateProofKey && algoTxn.stateProofKey.toString('base64')
      );
    }
  }

  private isNonParticipationKeyRegAlgoSDKTransaction(algoTxn: algosdk.Transaction): boolean {
    return !!algoTxn.nonParticipation;
  }

  private isNonParticipationKeyRegAccountLibTransaction(): boolean {
    return !!this._nonParticipation;
  }

  private isOnlineKeyRegAlgoSDKTransaction(algoTxn: algosdk.Transaction): boolean {
    return !(
      this.isOfflineKeyRegAlgoSDKTransaction(algoTxn) || this.isNonParticipationKeyRegAlgoSDKTransaction(algoTxn)
    );
  }

  private isOnlineKeyRegAccountLibTransaction(): boolean {
    return !(this.isOfflineKeyRegAccountLibTransaction() || this.isNonParticipationKeyRegAccountLibTransaction());
  }

  private isOfflineKeyRegAlgoSDKTransaction(algoTxn: algosdk.Transaction): boolean {
    return (
      !algoTxn.voteKey &&
      !algoTxn.selectionKey &&
      !algoTxn.voteFirst &&
      !algoTxn.voteLast &&
      !algoTxn.voteKeyDilution &&
      !algoTxn.stateProofKey &&
      !algoTxn.nonParticipation
    );
  }

  private isOfflineKeyRegAccountLibTransaction(): boolean {
    return (
      !this._voteKey &&
      !this._selectionKey &&
      !this._voteFirst &&
      !this._voteLast &&
      !this._voteKeyDilution &&
      !this._stateProofKey &&
      !this._nonParticipation
    );
  }

  /** @inheritdoc */
  validateTransaction(transaction: Transaction): void {
    super.validateTransaction(transaction);
    if (this.isOnlineKeyRegAccountLibTransaction()) {
      // invalid offline will reach here
      this.validateFields(
        this._voteKey,
        this._selectionKey,
        this._voteFirst,
        this._voteLast,
        this._voteKeyDilution,
        this._stateProofKey
      );
    } else {
      // offline or nonparticipation transaction
      if (
        this._voteKey ||
        this._selectionKey ||
        this._voteFirst ||
        this._voteLast ||
        this._voteKeyDilution ||
        this._stateProofKey
      ) {
        throw new InvalidTransactionError(
          'VoteKey, SelectionKey, VoteFirst, VoteLast, VoteKeyDilution, StateProofKey fields cannot be set when offline or nonparticipation is set'
        );
      }
    }
  }

  private validateFields(
    voteKey: string,
    selectionKey: string,
    voteFirst: number,
    voteLast: number,
    voteKeyDilution: number,
    stateProofKey?: string
  ): void {
    const validationResult = KeyRegTxnSchema.validate({
      voteKey,
      selectionKey,
      voteFirst,
      voteLast,
      voteKeyDilution,
      stateProofKey,
    });

    if (validationResult.error) {
      throw new InvalidTransactionError(`Transaction validation failed: ${validationResult.error.message}`);
    }
  }
}

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


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