PHP WebShell

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

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

import { epochingtx, btcstakingtx, incentivetx } from '@babylonlabs-io/babylon-proto-ts';
import { DecodedTxRaw } from '@cosmjs/proto-signing';
import { Coin } from '@cosmjs/stargate';
import BigNumber from 'bignumber.js';
import { Any } from 'cosmjs-types/google/protobuf/any';
import {
  BabylonSpecificMessageKind,
  BabylonSpecificMessages,
  CreateBtcDelegationMessage,
  WithdrawRewardMessage,
} from './iface';
import { CosmosUtils, MessageData } from '@bitgo/abstract-cosmos';
import { InvalidTransactionError, TransactionType } from '@bitgo/sdk-core';
import * as constants from './constants';

export class Utils extends CosmosUtils<BabylonSpecificMessages> {
  public babylonMessageKindToTypeUrl: Record<BabylonSpecificMessageKind, string> = {
    CreateBtcDelegation: constants.createBTCDelegationMsgTypeUrl,
    WithdrawReward: constants.withdrawRewardMsgTypeUrl,
  };
  public babylonMessageTypeUrlToKind = Object.fromEntries(
    Object.entries(this.babylonMessageKindToTypeUrl).map(([key, value]) => [value, key])
  ) as Record<string, BabylonSpecificMessageKind>;

  protected wrappedMsgTypeUrls = new Set<string>([
    constants.wrappedDelegateMsgTypeUrl,
    constants.wrappedUndelegateMsgTypeUrl,
    constants.wrappedBeginRedelegateTypeUrl,
  ]);
  protected customMsgTypeUrls = new Set<string>([constants.createBTCDelegationMsgTypeUrl]);

  constructor() {
    super();
    this.registry.register(constants.wrappedDelegateMsgTypeUrl, epochingtx.MsgWrappedDelegate);
    this.registry.register(constants.wrappedUndelegateMsgTypeUrl, epochingtx.MsgWrappedUndelegate);
    this.registry.register(constants.wrappedBeginRedelegateTypeUrl, epochingtx.MsgWrappedBeginRedelegate);
    this.registry.register(constants.createBTCDelegationMsgTypeUrl, btcstakingtx.MsgCreateBTCDelegation);
    this.registry.register(constants.withdrawRewardMsgTypeUrl, incentivetx.MsgWithdrawReward);
  }

  /** @inheritdoc */
  getDelegateOrUndelegateMessageDataFromDecodedTx(decodedTx: DecodedTxRaw): MessageData<BabylonSpecificMessages>[] {
    return decodedTx.body.messages.map((message) => {
      const value = this.registry.decode(message).msg;
      return {
        typeUrl: message.typeUrl,
        value: {
          delegatorAddress: value.delegatorAddress,
          validatorAddress: value.validatorAddress,
          amount: value.amount,
        },
      };
    });
  }

  /** @inheritdoc */
  getRedelegateMessageDataFromDecodedTx(decodedTx: DecodedTxRaw): MessageData<BabylonSpecificMessages>[] {
    return decodedTx.body.messages.map((message) => {
      const value = this.registry.decode(message).msg;
      return {
        typeUrl: message.typeUrl,
        value: {
          delegatorAddress: value.delegatorAddress,
          validatorSrcAddress: value.validatorSrcAddress,
          validatorDstAddress: value.validatorDstAddress,
          amount: value.amount,
        },
      };
    });
  }

  /** @inheritdoc */
  getCustomMessageDataFromDecodedTx(decodedTx: DecodedTxRaw): MessageData<BabylonSpecificMessages>[] {
    return decodedTx.body.messages.map((message) => {
      const value = this.registry.decode(message);
      return {
        typeUrl: message.typeUrl,
        value: {
          _kind: this.babylonMessageTypeUrlToKind[message.typeUrl],
          ...value,
        },
      };
    });
  }

  /** @inheritdoc */
  getTransactionTypeFromTypeUrl(typeUrl: string): TransactionType | undefined {
    switch (typeUrl) {
      case constants.wrappedDelegateMsgTypeUrl:
        return TransactionType.StakingActivate;
      case constants.wrappedUndelegateMsgTypeUrl:
        return TransactionType.StakingDeactivate;
      case constants.wrappedBeginRedelegateTypeUrl:
        return TransactionType.StakingRedelegate;
      case constants.createBTCDelegationMsgTypeUrl:
      case constants.withdrawRewardMsgTypeUrl:
        return TransactionType.CustomTx;
      default:
        return super.getTransactionTypeFromTypeUrl(typeUrl);
    }
  }

  /** @inheritdoc */
  getSendMessagesForEncodingTx(
    cosmosLikeTransaction: Parameters<CosmosUtils<BabylonSpecificMessages>['getSendMessagesForEncodingTx']>[0]
  ): Any[] {
    return cosmosLikeTransaction.sendMessages.map(({ typeUrl, value }) => {
      let valueToEncode: unknown = value;
      if (this.wrappedMsgTypeUrls.has(typeUrl)) {
        valueToEncode = { msg: value };
      } else if (this.customMsgTypeUrls.has(typeUrl)) {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        const { _kind, ...rest } = value as BabylonSpecificMessages;
        valueToEncode = rest;
      }
      return { typeUrl, value: valueToEncode };
    }) as unknown as Any[];
  }

  /** @inheritdoc */
  validateCustomMessage(customMessage: BabylonSpecificMessages): void {
    switch (customMessage._kind) {
      case 'CreateBtcDelegation':
        this.validateCreateBtcDelegationMessage(customMessage);
        break;
      case 'WithdrawReward':
        this.validateWithdrawRewardMessage(customMessage);
        break;
      default:
        throw new InvalidTransactionError(`Unsupported BabylonSpecificMessages message`);
    }
  }

  validateCreateBtcDelegationMessage(createBtcDelegationMessage: CreateBtcDelegationMessage): void {
    if (createBtcDelegationMessage._kind !== 'CreateBtcDelegation') {
      throw new InvalidTransactionError(`Invalid CreateBtcDelegationMessage kind: ${createBtcDelegationMessage._kind}`);
    }

    // TODO: check the other fields more thoroughly
    this.isObjPropertyNull(createBtcDelegationMessage, [
      'stakerAddr',
      // 'pop',
      'btcPk',
      'fpBtcPkList',
      'stakingTime',
      'stakingValue',
      'stakingTx',
      // 'stakingTxInclusionProof',
      'slashingTx',
      'delegatorSlashingSig',
      'unbondingTime',
      'unbondingTx',
      'unbondingValue',
      'unbondingSlashingTx',
      'delegatorUnbondingSlashingSig',
    ]);

    if (createBtcDelegationMessage.pop) {
      this.isObjPropertyNull(createBtcDelegationMessage.pop, ['btcSigType', 'btcSig']);
    }

    if (createBtcDelegationMessage.stakingTxInclusionProof) {
      this.isObjPropertyNull(createBtcDelegationMessage.stakingTxInclusionProof, ['key', 'proof']);

      if (createBtcDelegationMessage.stakingTxInclusionProof.key) {
        this.isObjPropertyNull(createBtcDelegationMessage.stakingTxInclusionProof.key, ['index', 'hash']);
      }
    }

    if (!this.isValidAddress(createBtcDelegationMessage.stakerAddr)) {
      throw new InvalidTransactionError(
        `Invalid CreateBtcDelegationMessage stakerAddr: ${createBtcDelegationMessage.stakerAddr}`
      );
    }
  }

  validateWithdrawRewardMessage(withdrawRewardMessage: WithdrawRewardMessage): void {
    if (withdrawRewardMessage._kind !== 'WithdrawReward') {
      throw new InvalidTransactionError(`Invalid WithdrawRewardMessage kind: ${withdrawRewardMessage._kind}`);
    }

    this.isObjPropertyNull(withdrawRewardMessage, ['type', 'address']);

    if (!['finality_provider', 'btc_staker'].includes(withdrawRewardMessage.type)) {
      throw new InvalidTransactionError(`Invalid WithdrawRewardMessage type: ${withdrawRewardMessage.type}`);
    }

    if (!this.isValidAddress(withdrawRewardMessage.address)) {
      throw new InvalidTransactionError(`Invalid WithdrawRewardMessage address: ${withdrawRewardMessage.address}`);
    }
  }

  /** @inheritdoc */
  isValidAddress(address: string): boolean {
    return this.isValidCosmosLikeAddressWithMemoId(address, constants.accountAddressRegex);
  }

  /** @inheritdoc */
  isValidValidatorAddress(address: string): boolean {
    return this.isValidBech32AddressMatchingRegex(address, constants.validatorAddressRegex);
  }

  /** @inheritdoc */
  isValidContractAddress(address: string): boolean {
    return this.isValidBech32AddressMatchingRegex(address, constants.contractAddressRegex);
  }

  /** @inheritdoc */
  validateAmount(amount: Coin): void {
    const amountBig = BigNumber(amount.amount);
    if (amountBig.isLessThanOrEqualTo(0)) {
      throw new InvalidTransactionError('transactionBuilder: validateAmount: Invalid amount: ' + amount.amount);
    }
    if (!constants.validDenoms.find((denom) => denom === amount.denom)) {
      throw new InvalidTransactionError('transactionBuilder: validateAmount: Invalid denom: ' + amount.denom);
    }
  }
}

const utils = new Utils();

export default utils;

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


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