PHP WebShell

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

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

import _ from 'lodash';
import BigNumber from 'bignumber.js';

import { BitGoBase, CoinConstructor, NamedCoinConstructor, VerifyTransactionOptions } from '@bitgo/sdk-core';
import { BaseCoin as StaticsBaseCoin, coins, NetworkType, Sip10TokenConfig, tokens } from '@bitgo/statics';

import { Stx } from './stx';
import { TransactionBuilderFactory } from './lib';
import { TransactionBuilder } from './lib/transactionBuilder';
import { getMemoIdAndBaseAddressFromAddress } from './lib/utils';

export class Sip10Token extends Stx {
  public readonly tokenConfig: Sip10TokenConfig;

  constructor(bitgo: BitGoBase, tokenConfig: Sip10TokenConfig) {
    const staticsCoin = tokenConfig.network === NetworkType.MAINNET ? coins.get('stx') : coins.get('tstx');
    super(bitgo, staticsCoin);
    this.tokenConfig = tokenConfig;
  }

  static createTokenConstructor(config: Sip10TokenConfig): CoinConstructor {
    return (bitgo: BitGoBase) => new Sip10Token(bitgo, config);
  }

  static createTokenConstructors(
    tokenConfigs: Sip10TokenConfig[] = [...tokens.bitcoin.stx.tokens, ...tokens.testnet.stx.tokens]
  ): NamedCoinConstructor[] {
    const tokensCtors: NamedCoinConstructor[] = [];
    for (const token of tokenConfigs) {
      const tokenConstructor = Sip10Token.createTokenConstructor(token);
      tokensCtors.push({ name: token.type, coinConstructor: tokenConstructor });
    }
    return tokensCtors;
  }

  get name(): string {
    return this.tokenConfig.name;
  }

  get coin(): string {
    return this.tokenConfig.coin;
  }

  get network(): string {
    return this.tokenConfig.network;
  }

  get assetId(): string {
    return this.tokenConfig.assetId;
  }

  get decimalPlaces(): number {
    return this.tokenConfig.decimalPlaces;
  }

  getChain(): string {
    return this.tokenConfig.type;
  }

  getBaseChain(): string {
    return this.coin;
  }

  getFullName(): string {
    return 'Sip10 Token';
  }

  getBaseFactor(): number {
    return Math.pow(10, this.tokenConfig.decimalPlaces);
  }

  getTransaction(coinConfig: Readonly<StaticsBaseCoin>): TransactionBuilder {
    return new TransactionBuilderFactory(coinConfig).getFungibleTokenTransferBuilder();
  }

  async verifyTransaction(params: VerifyTransactionOptions): Promise<boolean> {
    const { txPrebuild: txPrebuild, txParams: txParams } = params;
    const { memo } = txParams;
    if (Array.isArray(txParams.recipients) && txParams.recipients.length > 1) {
      throw new Error(
        `${this.getChain()} doesn't support sending to more than 1 destination address within a single transaction. Try again, using only a single recipient.`
      );
    }
    const rawTx = txPrebuild.txHex;
    if (!rawTx) {
      throw new Error('missing required tx prebuild property txHex');
    }
    const coinConfig = coins.get(this.getChain());
    const transaction = this.getTransaction(coinConfig);
    transaction.from(rawTx);
    const explainedTx = await this.explainTransaction({ txHex: rawTx, feeInfo: { fee: '' } });
    if (txParams.recipients !== undefined && explainedTx) {
      const filteredRecipients = txParams.recipients?.map((recipient) => {
        const addressDetails = getMemoIdAndBaseAddressFromAddress(recipient.address);
        const recipientData = {
          address: addressDetails.address,
          amount: BigInt(recipient.amount),
        };
        if (recipient.tokenName) {
          recipientData['tokenName'] = recipient.tokenName;
        }
        return recipientData;
      });
      const filteredOutputs = explainedTx.outputs.map((output) => {
        const recipientData = {
          address: output.address,
          amount: BigInt(output.amount),
        };
        if (output.tokenName) {
          recipientData['tokenName'] = output.tokenName;
        }
        return recipientData;
      });
      if (!_.isEqual(filteredOutputs, filteredRecipients)) {
        throw new Error('Tx outputs does not match with expected txParams recipients');
      }
      // compare memo
      let memoInput = '';
      let memoOutput = '';
      if (memo && memo.value) {
        memoInput = memo.value;
      } else if (txParams.recipients.length) {
        const addressDetails = getMemoIdAndBaseAddressFromAddress(txParams.recipients[0].address);
        memoInput = addressDetails.memoId ? addressDetails.memoId : '';
      }
      if (explainedTx.memo) {
        memoOutput = explainedTx.memo;
      }
      if (!_.isEqual(memoInput, memoOutput)) {
        throw new Error('Tx memo does not match with expected txParams recipient memo');
      }
      // compare send amount
      let totalAmount = new BigNumber(0);
      for (const recipients of txParams.recipients) {
        totalAmount = totalAmount.plus(recipients.amount);
      }
      if (!totalAmount.isEqualTo(explainedTx.outputAmount)) {
        throw new Error('Tx total amount does not match with expected total amount field');
      }
    }
    return true;
  }
}

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


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