PHP WebShell

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

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

import * as utxolib from '@bitgo/utxo-lib';
import { ITransactionRecipient } from '@bitgo/sdk-core';
import * as coreDescriptors from '@bitgo/utxo-core/descriptor';

import {
  AbstractUtxoCoin,
  BaseOutput,
  BaseParsedTransaction,
  BaseParsedTransactionOutputs,
  ParseTransactionOptions,
} from '../../abstractUtxoCoin';
import { getKeySignatures, toBip32Triple, UtxoNamedKeychains } from '../../keychains';
import { getDescriptorMapFromWallet, getPolicyForEnv } from '../../descriptor';
import { IDescriptorWallet } from '../../descriptor/descriptorWallet';
import { fromExtendedAddressFormatToScript, toExtendedAddressFormat } from '../recipient';
import { outputDifferencesWithExpected, OutputDifferenceWithExpected } from '../outputDifference';

type ParsedOutput = coreDescriptors.ParsedOutput;

export type RecipientOutput = Omit<ParsedOutput, 'value'> & {
  value: bigint | 'max';
};

function toRecipientOutput(recipient: ITransactionRecipient, network: utxolib.Network): RecipientOutput {
  return {
    address: recipient.address,
    value: recipient.amount === 'max' ? 'max' : BigInt(recipient.amount),
    script: fromExtendedAddressFormatToScript(recipient.address, network),
  };
}

// TODO(BTC-1697): allow outputs with `value: 'max'` here
type ParsedOutputs = OutputDifferenceWithExpected<ParsedOutput, RecipientOutput> & {
  outputs: ParsedOutput[];
  changeOutputs: ParsedOutput[];
};

function parseOutputsWithPsbt(
  psbt: utxolib.bitgo.UtxoPsbt,
  descriptorMap: coreDescriptors.DescriptorMap,
  recipientOutputs: RecipientOutput[]
): ParsedOutputs {
  const parsed = coreDescriptors.parse(psbt, descriptorMap, psbt.network);
  const changeOutputs = parsed.outputs.filter((o) => o.scriptId !== undefined);
  const outputDiffs = outputDifferencesWithExpected(parsed.outputs, recipientOutputs);
  return {
    outputs: parsed.outputs,
    changeOutputs,
    ...outputDiffs,
  };
}

function sumValues(arr: { value: bigint }[]): bigint {
  return arr.reduce((sum, e) => sum + e.value, BigInt(0));
}

function toBaseOutputs(outputs: ParsedOutput[], network: utxolib.Network): BaseOutput<bigint>[];
function toBaseOutputs(outputs: RecipientOutput[], network: utxolib.Network): BaseOutput<bigint | 'max'>[];
function toBaseOutputs(
  outputs: (ParsedOutput | RecipientOutput)[],
  network: utxolib.Network
): BaseOutput<bigint | 'max'>[] {
  return outputs.map(
    (o): BaseOutput<bigint | 'max'> => ({
      address: toExtendedAddressFormat(o.script, network),
      amount: o.value === 'max' ? 'max' : BigInt(o.value),
      external: o.scriptId === undefined,
    })
  );
}

export type ParsedOutputsBigInt = BaseParsedTransactionOutputs<bigint, BaseOutput<bigint | 'max'>>;

function toBaseParsedTransactionOutputs(
  { outputs, changeOutputs, explicitOutputs, implicitOutputs, missingOutputs }: ParsedOutputs,
  network: utxolib.Network
): ParsedOutputsBigInt {
  const explicitExternalOutputs = explicitOutputs.filter((o) => o.scriptId === undefined);
  const implicitExternalOutputs = implicitOutputs.filter((o) => o.scriptId === undefined);
  return {
    outputs: toBaseOutputs(outputs, network),
    changeOutputs: toBaseOutputs(changeOutputs, network),
    explicitExternalOutputs: toBaseOutputs(explicitExternalOutputs, network),
    explicitExternalSpendAmount: sumValues(explicitExternalOutputs),
    implicitExternalOutputs: toBaseOutputs(implicitExternalOutputs, network),
    implicitExternalSpendAmount: sumValues(implicitExternalOutputs),
    missingOutputs: toBaseOutputs(missingOutputs, network),
  };
}

export function toBaseParsedTransactionOutputsFromPsbt(
  psbt: utxolib.bitgo.UtxoPsbt,
  descriptorMap: coreDescriptors.DescriptorMap,
  recipients: ITransactionRecipient[],
  network: utxolib.Network
): ParsedOutputsBigInt {
  return toBaseParsedTransactionOutputs(
    parseOutputsWithPsbt(
      psbt,
      descriptorMap,
      recipients.map((r) => toRecipientOutput(r, psbt.network))
    ),
    network
  );
}

export type ParsedDescriptorTransaction<TAmount extends number | bigint> = BaseParsedTransaction<
  TAmount,
  BaseOutput<TAmount | 'max'>
>;

export function parse(
  coin: AbstractUtxoCoin,
  wallet: IDescriptorWallet,
  params: ParseTransactionOptions<number | bigint>
): ParsedDescriptorTransaction<bigint> {
  if (params.txParams.allowExternalChangeAddress) {
    throw new Error('allowExternalChangeAddress is not supported for descriptor wallets');
  }
  if (params.txParams.changeAddress) {
    throw new Error('changeAddress is not supported for descriptor wallets');
  }
  const keychains = params.verification?.keychains;
  if (!keychains || !UtxoNamedKeychains.is(keychains)) {
    throw new Error('keychain is required for descriptor wallets');
  }
  const { recipients } = params.txParams;
  if (!recipients) {
    throw new Error('recipients is required');
  }
  const psbt = coin.decodeTransactionFromPrebuild(params.txPrebuild);
  if (!(psbt instanceof utxolib.bitgo.UtxoPsbt)) {
    throw new Error('expected psbt to be an instance of UtxoPsbt');
  }
  const walletKeys = toBip32Triple(keychains);
  const descriptorMap = getDescriptorMapFromWallet(wallet, walletKeys, getPolicyForEnv(params.wallet.bitgo.env));
  return {
    ...toBaseParsedTransactionOutputsFromPsbt(psbt, descriptorMap, recipients, psbt.network),
    keychains,
    keySignatures: getKeySignatures(wallet) ?? {},
    customChange: undefined,
    needsCustomChangeKeySignatureVerification: false,
  };
}

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


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