PHP WebShell

Текущая директория: /opt/BitGoJS/modules/utxo-lib/test/bitgo/psbt

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

import * as assert from 'assert';

import * as bs58check from 'bs58check';

import { fromOutputScript } from '../../../src/address';
import { createOutputScriptP2shP2pk, scriptTypes2Of3 } from '../../../src/bitgo/outputScripts';
import { getDefaultWalletKeys, getKeyTriple, replayProtectionKeyPair } from '../../../src/testutil';
import { networks, testutil } from '../../../src';
import { addWalletOutputToPsbt, addXpubsToPsbt, getExternalChainCode, RootWalletKeys } from '../../../src/bitgo';
import {
  findInternalOutputIndices,
  findWalletOutputIndices,
  getTotalAmountOfInternalOutputs,
  getTotalAmountOfWalletOutputs,
} from '../../../src/bitgo/wallet/psbt/PsbtOutputs';
import { GlobalXpub } from 'bip174/src/lib/interfaces';

const network = networks.bitcoin;
const rootWalletKeys = getDefaultWalletKeys();

describe('psbt internal and wallet outputs', function () {
  const value = BigInt(1e8);
  const fee = BigInt(1000);
  const externalAddress = fromOutputScript(
    createOutputScriptP2shP2pk(replayProtectionKeyPair.publicKey).scriptPubKey,
    networks.bitcoin
  );

  describe('success', function () {
    it(`Find indices of psbt wallet & internal outputs`, function () {
      const psbt = testutil.constructPsbt(
        [
          { scriptType: 'p2wsh', value: BigInt(value + value) },
          { scriptType: 'p2shP2wsh', value: BigInt(value) },
          { scriptType: 'p2trMusig2', value: BigInt(value) },
          { scriptType: 'p2tr', value: BigInt(value) },
          { scriptType: 'p2sh', value: BigInt(value) },
        ],
        [
          { scriptType: 'p2sh', value: BigInt(value) },
          { scriptType: 'p2shP2wsh', value: BigInt(value) },
          { scriptType: 'p2wsh', value: BigInt(value) },
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
          { scriptType: 'p2tr', value: BigInt(value), isInternalAddress: true },
          { scriptType: 'p2trMusig2', value: BigInt(value), isInternalAddress: true },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );
      const expected = [0, 1, 2, 4, 5];
      assert.deepEqual(findWalletOutputIndices(psbt, rootWalletKeys.triple), expected);
      addXpubsToPsbt(psbt, rootWalletKeys);
      assert.deepEqual(findInternalOutputIndices(psbt), expected);
    });

    scriptTypes2Of3.forEach((scriptType) => {
      const psbt = testutil.constructPsbt(
        [
          { scriptType: scriptType, value: BigInt(value) },
          { scriptType: 'p2wsh', value: BigInt(value) },
          { scriptType: 'p2shP2wsh', value: BigInt(value) },
          { scriptType: 'p2trMusig2', value: BigInt(value) },
          { scriptType: 'p2tr', value: BigInt(value) },
          { scriptType: 'p2sh', value: BigInt(value) },
        ],
        [
          { scriptType: 'p2sh', value: BigInt(value) },
          { scriptType: 'p2shP2wsh', value: BigInt(value) },
          { scriptType: 'p2wsh', value: BigInt(value) },
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
          { scriptType: 'p2tr', value: BigInt(value), isInternalAddress: true },
          { scriptType: 'p2trMusig2', value: BigInt(value), isInternalAddress: true },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );

      addXpubsToPsbt(psbt, rootWalletKeys);

      const totalInternalAmount = value * BigInt(psbt.inputCount - 1);

      it(`PSBT with ${scriptType} input and globalXpub`, function () {
        assert.strictEqual(getTotalAmountOfInternalOutputs(psbt), totalInternalAmount);
      });

      it(`Cloned PSBT with ${scriptType} input and globalXpub`, function () {
        assert.strictEqual(getTotalAmountOfInternalOutputs(psbt.clone()), totalInternalAmount);
      });

      it(`PSBT with ${scriptType} input and ordered rootNodes`, function () {
        assert.strictEqual(getTotalAmountOfWalletOutputs(psbt, rootWalletKeys.triple), totalInternalAmount);
      });
    });

    it(`PSBT with p2shP2pk as first input`, function () {
      const psbt = testutil.constructPsbt(
        [
          { scriptType: 'p2shP2pk', value: BigInt(value) },
          { scriptType: 'p2wsh', value: BigInt(value) },
        ],
        [
          { scriptType: 'p2sh', value: BigInt(value) },
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );
      addXpubsToPsbt(psbt, rootWalletKeys);
      assert.strictEqual(getTotalAmountOfInternalOutputs(psbt), value);
    });

    it(`PSBT with outputs of external wallet root nodes`, function () {
      const psbt = testutil.constructPsbt(
        [{ scriptType: 'p2wsh', value: BigInt(value) }],
        [{ scriptType: 'p2sh', value: BigInt(value) }],
        network,
        rootWalletKeys,
        'unsigned'
      );
      const externalAmount = BigInt(8888);
      const externalRootWalletKeys = new RootWalletKeys(getKeyTriple('dummy'));
      const indices = [0, 1];
      indices.forEach((index) =>
        addWalletOutputToPsbt(psbt, externalRootWalletKeys, getExternalChainCode('p2wsh'), index, externalAmount)
      );
      assert.strictEqual(
        getTotalAmountOfWalletOutputs(psbt, externalRootWalletKeys.triple),
        externalAmount * BigInt(indices.length)
      );
    });

    it(`PSBT with no outputs of external wallet root nodes`, function () {
      const psbt = testutil.constructPsbt(
        [{ scriptType: 'p2wsh', value: BigInt(value) }],
        [{ scriptType: 'p2sh', value: BigInt(value) }],
        network,
        rootWalletKeys,
        'unsigned'
      );
      assert.strictEqual(
        getTotalAmountOfWalletOutputs(psbt, new RootWalletKeys(getKeyTriple('dummy')).triple),
        BigInt(0)
      );
    });

    it(`PSBT with no internal output`, function () {
      const psbt = testutil.constructPsbt(
        [{ scriptType: 'p2wsh', value: BigInt(value) }],
        [
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );
      addXpubsToPsbt(psbt, rootWalletKeys);
      assert.strictEqual(getTotalAmountOfInternalOutputs(psbt), BigInt(0));
    });
  });

  describe('failure', function () {
    it('PSBT without globalXpub', function () {
      const psbt = testutil.constructPsbt([], [], network, rootWalletKeys, 'unsigned');
      assert.throws(
        () => getTotalAmountOfInternalOutputs(psbt),
        (e: any) => e.message === 'Could not find root nodes in PSBT'
      );
    });

    it('PSBT with invalid number of globalXpub', function () {
      const psbt = testutil.constructPsbt([], [], network, rootWalletKeys, 'unsigned');
      const globalXpub: GlobalXpub[] = [
        {
          extendedPubkey: bs58check.decode(rootWalletKeys.triple[0].neutered().toBase58()),
          masterFingerprint: rootWalletKeys.triple[0].fingerprint,
          path: 'm',
        },
      ];
      psbt.updateGlobal({ globalXpub });
      assert.throws(
        () => getTotalAmountOfInternalOutputs(psbt),
        (e: any) => e.message === 'Invalid globalXpubs in PSBT. Expected 3 or none. Got 1'
      );
    });

    it('PSBT without input scriptPubKey', function () {
      const psbt = testutil.constructPsbt(
        [{ scriptType: 'p2wsh', value: BigInt(value) }],
        [
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );
      psbt.data.inputs[0].witnessUtxo = undefined;
      addXpubsToPsbt(psbt, rootWalletKeys);
      assert.throws(
        () => getTotalAmountOfInternalOutputs(psbt),
        (e: any) => e.message === 'Input scriptPubKey can not be found'
      );
    });

    it('PSBT without input Bip32Derivation', function () {
      const psbt = testutil.constructPsbt(
        [{ scriptType: 'p2wsh', value: BigInt(value) }],
        [
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );
      psbt.data.inputs[0].bip32Derivation = undefined;
      addXpubsToPsbt(psbt, rootWalletKeys);
      assert.throws(
        () => getTotalAmountOfInternalOutputs(psbt),
        (e: any) => e.message === 'Input Bip32Derivation can not be found'
      );
    });

    it('PSBT woth an OP_RETURN output', function () {
      const opReturnScript =
        '6a4c505341542b01045bde60b7d0e6b758ca5dd8c61d377a2c5f1af51ec1a9e209f5ea0036c8c2f41078a3cebee57d8a47d501041f5e0e66b17576a914c4b8ae927ff2b9ce218e20bf06d425d6b68424fd88ac';
      const psbt = testutil.constructPsbt(
        [{ scriptType: 'p2wsh', value: BigInt(value) }],
        [
          {
            address: externalAddress,
            value: BigInt(value - fee),
          },
          {
            script: opReturnScript,
            value: BigInt(0),
          },
        ],
        network,
        rootWalletKeys,
        'unsigned'
      );
      const tx = psbt.getUnsignedTx();
      assert.strictEqual(tx.outs.length, 2);
      const out = tx.outs[1];
      assert.strictEqual(out.value, BigInt(0));
      assert.strictEqual(out.script.toString('hex'), opReturnScript);
    });
  });
});

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


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