PHP WebShell

Текущая директория: /opt/BitGoJS/modules/sdk-coin-icp/test/unit/transactionBuilder

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

import should from 'should';
import * as testData from '../../resources/icp';
import { getBuilderFactory } from '../getBuilderFactory';
import sinon from 'sinon';
import { TestBitGo } from '@bitgo/sdk-test';
import { BitGoAPI } from '@bitgo/sdk-api';
import nock from 'nock';
import { Icp } from '../../../src/index';
import { RecoveryOptions, ACCOUNT_BALANCE_ENDPOINT, LEDGER_CANISTER_ID } from '../../../src/lib/iface';
import { Principal } from '@dfinity/principal';

describe('ICP transaction recovery', async () => {
  let bitgo;
  let recoveryParams: RecoveryOptions;
  let icp;
  let broadcastEndpoint: string;
  let broadcastResponse: Buffer;
  let nodeUrl: string;
  let rosettaNodeUrl: string;
  let txBuilder: any;
  const factory = getBuilderFactory('ticp');

  before(function () {
    bitgo = TestBitGo.decorate(BitGoAPI, { env: 'test' });
    bitgo.safeRegister('icp', Icp.createInstance);
    bitgo.initializeTestVars();
    recoveryParams = {
      userKey: testData.WRWRecovery.userKey,
      backupKey: testData.WRWRecovery.backupKey,
      walletPassphrase: testData.WRWRecovery.walletPassphrase,
      recoveryDestination: testData.Accounts.account2.address,
    };

    icp = bitgo.coin('icp');
    rosettaNodeUrl = icp.getRosettaNodeUrl();
    nodeUrl = icp.getPublicNodeUrl();
    const principal = Principal.fromUint8Array(LEDGER_CANISTER_ID);
    const canisterIdHex = principal.toText();
    broadcastEndpoint = `/api/v3/canister/${canisterIdHex}/call`;
    broadcastResponse = Buffer.from(testData.PublicNodeApiBroadcastResponse, 'hex');
  });

  afterEach(function () {
    recoveryParams = {
      userKey: testData.WRWRecovery.userKey,
      backupKey: testData.WRWRecovery.backupKey,
      walletPassphrase: testData.WRWRecovery.walletPassphrase,
      recoveryDestination: testData.Accounts.account2.address,
    };
    nock.cleanAll();
    sinon.restore();
  });

  it('should recover a transaction with default memo successfully', async () => {
    txBuilder = factory.getTransferBuilder();

    // Stub the getTransferBuilder to return our txBuilder
    //TODO need to have a better way for test cases WithDefault mocking these functions. TIcket: https://bitgoinc.atlassian.net/browse/WIN-5158
    sinon.stub(icp, 'getBuilderFactory').returns(factory);
    sinon.stub(factory, 'getTransferBuilder').returns(txBuilder);
    sinon.stub(icp, 'signatures').returns(testData.RecoverTransactionSignatureWithDefaultMemo);

    sinon.stub(txBuilder._utils, 'getMetaData').returns({
      metaData: testData.MetaDataWithDefaultMemo,
      ingressEndTime: testData.MetaDataWithDefaultMemo.ingress_end,
    });

    const body = testData.RecoverySignedTransactionWithDefaultMemo;
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);
    nock(nodeUrl).post(broadcastEndpoint, body).reply(200, broadcastResponse);
    const txnId = await icp.recover(recoveryParams);
    txnId.should.be.a.String();
    should.equal(txnId, testData.TxnId);
  });

  it('should recover a transaction with memo successfully', async () => {
    txBuilder = factory.getTransferBuilder();

    // Stub the getTransferBuilder to return our txBuilder
    sinon.stub(icp, 'getBuilderFactory').returns(factory);
    sinon.stub(factory, 'getTransferBuilder').returns(txBuilder);
    sinon.stub(icp, 'signatures').returns(testData.RecoverTransactionSignatureWithMemo);

    sinon.stub(txBuilder._utils, 'getMetaData').returns({
      metaData: testData.MetaDataWithMemo,
      ingressEndTime: testData.MetaDataWithMemo.ingress_end,
    });

    const body = testData.RecoverySignedTransactionWithMemo;
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);
    nock(nodeUrl).post(broadcastEndpoint, body).reply(200, broadcastResponse);
    recoveryParams.memo = testData.MetaDataWithMemo.memo;
    const txnId = await icp.recover(recoveryParams);
    txnId.should.be.a.String();
    should.equal(txnId, testData.TxnId);
  });

  it('should fail to recover if broadcast API fails', async () => {
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);
    nock(nodeUrl).post(broadcastEndpoint).reply(500, 'Internal Server Error');
    recoveryParams.memo = 0;
    await icp
      .recover(recoveryParams)
      .should.rejectedWith('Transaction broadcast error: Request failed with status code 500');
  });

  it('should fail to recover txn if balance is low', async () => {
    testData.GetAccountBalanceResponse.balances[0].value = '0';
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);
    nock(nodeUrl).post(broadcastEndpoint).reply(200, broadcastResponse);
    await icp.recover(recoveryParams).should.rejectedWith('Did not have enough funds to recover');
  });

  it('should fail to recover txn if userKey is not provided', async () => {
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);

    recoveryParams.userKey = '';
    await icp.recover(recoveryParams).should.rejectedWith('missing userKey');
  });

  it('should fail to recover txn if backupKey is not provided', async () => {
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);

    recoveryParams.backupKey = '';
    await icp.recover(recoveryParams).should.rejectedWith('missing backupKey');
  });

  it('should fail to recover txn if wallet passphrase is not provided', async () => {
    nock(rosettaNodeUrl).post(`${ACCOUNT_BALANCE_ENDPOINT}`).reply(200, testData.GetAccountBalanceResponse);

    recoveryParams.walletPassphrase = '';
    await icp.recover(recoveryParams).should.rejectedWith('missing wallet passphrase');
  });
});

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


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