PHP WebShell

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

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

/**
 * @prettier
 */
import { BitGoAPI } from '@bitgo/sdk-api';
import { Wallet } from '@bitgo/sdk-core';
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
import { bip32 } from '@bitgo/secp256k1';
import * as ecc from 'eosjs-ecc';
import * as _ from 'lodash';
import should from 'should';
import * as sinon from 'sinon';
import { Eos, Teos } from '../../src';
import { EosInputs, EosResponses } from '../fixtures';
import assert from 'assert';

describe('EOS:', function () {
  let bitgo: TestBitGoAPI;
  let basecoin;

  before(function () {
    bitgo = TestBitGo.decorate(BitGoAPI, { env: 'test' });
    bitgo.safeRegister('eos', Eos.createInstance);
    bitgo.safeRegister('teos', Teos.createInstance);
    bitgo.initializeTestVars();
    basecoin = bitgo.coin('teos');
  });

  it('should get address details', function () {
    let addressDetails = basecoin.getAddressDetails('i1skda3kso43');

    addressDetails.address.should.equal('i1skda3kso43');
    should(addressDetails.memoId).be.undefined();

    addressDetails = basecoin.getAddressDetails('ks13k3hdui24?memoId=1');
    addressDetails.address.should.equal('ks13k3hdui24');
    addressDetails.memoId.should.equal('1');

    (() => {
      basecoin.getAddressDetails('ks13k3hdui24?memoId=1&memoId=2');
    }).should.throw();
  });

  it('should get address details with alphanumeric memoid', function () {
    const addressDetails = basecoin.getAddressDetails('i1skda3kso43?memoId=123abc');

    addressDetails.address.should.equal('i1skda3kso43');
    addressDetails.memoId.should.equal('123abc');
  });

  it('should validate address', function () {
    basecoin.isValidAddress('i1skda3kso43').should.equal(true);
    basecoin.isValidAddress('ks13kdh245ls').should.equal(true);
    basecoin.isValidAddress('ks13k3hdui24?memoId=1').should.equal(true);
    basecoin.isValidAddress('ks13k3hdui24?memoId=x').should.equal(true);
  });

  it('verifyAddress should work', async function () {
    await basecoin.verifyAddress({
      address: 'i1skda3kso43',
      rootAddress: 'i1skda3kso43',
    });
    await basecoin.verifyAddress({
      address: 'ks13kdh245ls?memoId=1',
      rootAddress: 'ks13kdh245ls',
    });

    assert.rejects(basecoin.verifyAddress({ address: 'i1skda3kso43=x', rootAddress: 'i1skda3kso43' }));
    assert.rejects(basecoin.verifyAddress({ address: 'i1skda3kso43?memoId=243432', rootAddress: 'ks13kdh245ls' }));
    assert.rejects(basecoin.verifyAddress({ address: 'i1skda3kso43' }));
  });

  it('should generate valid random addresses', () => {
    for (let i = 0; i < 100; i++) {
      const address = basecoin.generateRandomAddress();
      basecoin.isValidAddress(address).should.be.true();
    }
  });

  it('isValidMemo should work', function () {
    basecoin.isValidMemo({ value: '1' }).should.equal(true);
    basecoin.isValidMemo({ value: 'uno' }).should.equal(true);
    basecoin.isValidMemo({ value: EosInputs.string257CharsLong }).should.equal(false);
  });

  it('isValidMemoId should work', function () {
    basecoin.isValidMemoId('1').should.equal(true);
    basecoin.isValidMemoId('123abc').should.equal(true);
    basecoin.isValidMemoId(EosInputs.string257CharsLong).should.equal(false);
  });

  it('should validate pub key', () => {
    const { pub } = basecoin.keychains().create();
    basecoin.isValidPub(pub).should.equal(true);
  });

  describe('Keypairs:', () => {
    it('should generate a keypair from random seed', function () {
      const keyPair = basecoin.generateKeyPair();
      keyPair.should.have.property('pub');
      keyPair.should.have.property('prv');

      basecoin.isValidPub(keyPair.pub).should.equal(true);
      basecoin.isValidPrv(keyPair.prv).should.equal(true);
    });

    it('should generate a keypair from seed', function () {
      const seed = Buffer.from('c3b09c24731be2851b641d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex');
      const keyPair = basecoin.generateKeyPair(seed);

      keyPair.pub.should.equal(
        'xpub661MyMwAqRbcF2SUqUMiqxWGwaVX6sH4okTtX8jxJ1A14wfL8W7jZEoNE537JqSESXFpTcXCZahPz7RKQLpAEGsVp233dc5CffLSecpU13X'
      );
      keyPair.prv.should.equal(
        'xprv9s21ZrQH143K2YN1jSpiUpZYPYf2hQZDSXYHikLLjfd2C9LBaxoV1SUtNnZGnXeyJ6uFWMbQTfjXqVfgNqRBw5yyaCtBK1AM8PF3XZtKjQp'
      );
    });
  });

  it('should create unsigned recovery transaction without Bitgo', async function () {
    const userKey =
      'xpub661MyMwAqRbcH1oUADxatLuKkVjaDB2zTNJoZQsGVQEvoogpbXJw24QMokNwFKj9Qhci6KWaCcQKrzpL4LCQXXX3YpTQxgD9KLBjhDrUWo4';
    const backupKey =
      'xpub661MyMwAqRbcH1n6sgY29G7dAxL7twS8rt1jyuuQb1kfnA7s3FJPGoVqb9JenXkeJmC4jZ8iVscn3AH6MkYAVc61FTYCHpxv5cxWar5Jw3C';
    const rootAddress = 'i1skda3kso43';
    const destinationAddress = 'ks13kdh245ls';

    // mock responses to the block chain
    const sandBox = sinon.createSandbox();
    const callBack = sandBox.stub(Eos.prototype, <any>'getDataFromNode');
    callBack
      .withArgs({
        endpoint: '/v1/chain/get_account',
        payload: { account_name: rootAddress },
      })
      .resolves(EosResponses.getAccountResponseSuccess1);
    callBack
      .withArgs({
        endpoint: '/v1/chain/get_account',
        payload: { account_name: destinationAddress },
      })
      .resolves(EosResponses.getAccountResponseSuccess2);
    callBack
      .withArgs({
        endpoint: '/v1/chain/get_info',
      })
      .resolves(EosResponses.getInfoResponseSuccess1);
    callBack
      .withArgs({
        endpoint: '/v1/chain/get_block',
        payload: { block_num_or_id: 191839472 },
      })
      .resolves(EosResponses.getBlockResponseSuccess1);

    // can create unsigned recovery transaction
    const unsignedRecoveryTransaction = await basecoin.recover({
      userKey,
      backupKey,
      bitgoKey: 'key',
      recoveryDestination: destinationAddress,
      rootAddress,
    });
    unsignedRecoveryTransaction.recoveryAmount.should.equal('5.0000');
    unsignedRecoveryTransaction.transaction.signatures.length.should.equal(0);

    // coin and txHex fields are expected during recovery of unsigned transaction using OVC
    unsignedRecoveryTransaction.coin.should.equal('teos');
    unsignedRecoveryTransaction.txHex.should.equal(
      '2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a9107468408cdcdb60f03cf4a9e53c000000000100a6823403ea3055000000572d3ccdcd013008c5709804717000000000a8ed3232213008c57098047170806321a22538028650c300000000000004454f530000000000000000000000000000000000000000000000000000000000000000000000000000'
    );

    // destination address and root address can include memoId
    const unsignedRecoveryTransaction2 = await basecoin.recover({
      userKey,
      backupKey,
      bitgoKey: 'key',
      recoveryDestination: `${destinationAddress}?memoId=0`,
      rootAddress: `${rootAddress}?memoId=0`,
    });
    unsignedRecoveryTransaction2.recoveryAmount.should.equal('5.0000');
    unsignedRecoveryTransaction2.transaction.signatures.length.should.equal(0);

    // coin and txHex fields are expected during recovery of unsigned transaction using OVC
    unsignedRecoveryTransaction.coin.should.equal('teos');
    unsignedRecoveryTransaction.txHex.should.equal(
      '2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a9107468408cdcdb60f03cf4a9e53c000000000100a6823403ea3055000000572d3ccdcd013008c5709804717000000000a8ed3232213008c57098047170806321a22538028650c300000000000004454f530000000000000000000000000000000000000000000000000000000000000000000000000000'
    );

    sandBox.restore();
  });

  describe('Transactions:', function () {
    const testExplainTransaction = (input, expectedOutput) =>
      async function () {
        const explainedTransaction = await basecoin.explainTransaction(input);
        should.exist(explainedTransaction);
        explainedTransaction.should.deepEqual(expectedOutput);
      };
    it('should generate a valid transaction signature', async function () {
      const signatureData = 'abcd';
      const tx = {
        txHex: signatureData,
        headers: {
          ref_block_num: 1,
          ref_block_prefix: 'asd',
        },
        transaction: {
          signatures: [],
          packed_trx: signatureData,
          compression: 'none',
        },
        recipients: [{}],
      };

      const seed = Buffer.from('c3b09c24731be2851b624d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex');
      const keyPair = basecoin.generateKeyPair(seed);

      const { halfSigned } = await basecoin.signTransaction({ txPrebuild: tx, prv: keyPair.prv });
      const signature = halfSigned.transaction.signatures[0];
      const hdNode = bip32.fromBase58(keyPair.pub);
      const eosPubkey = ecc.PublicKey.fromBuffer(hdNode.publicKey).toString();
      ecc.verify(signature, Buffer.from(signatureData, 'hex'), eosPubkey).should.eql(true);
    });

    it('should explain an EOS transaction', async function () {
      const explainTransactionParams = {
        headers: {
          ref_block_prefix: 100,
          ref_block_num: 995,
          expiration: '2018-04-27T18:40:34.000Z',
        },
        transaction: {
          packed_trx:
            'a26ee35ae30364000000000000000100a6823403ea3055000000572d3ccdcd019013e48c8ce5eed400000000a8ed3232229013e48c8ce5eed4b012362b61b31236640000000000000004454f5300000000013100',
        },
      };

      const explainedTx = await basecoin.explainTransaction(explainTransactionParams);
      explainedTx.outputAmount.should.equal('100');
      explainedTx.outputs.length.should.equal(1);
      explainedTx.outputs[0].amount.should.equal('100');
      explainedTx.outputs[0].address.should.equal('asdfasdfasdf');
      explainedTx.id.should.equal('6132f3bf4a746e6ecad8a31df67d71b4741fc5b7c868ae36dde18309a91df8a6');
      explainedTx.memo.should.equal('1');
    });
    it(
      'explains EOS native transfer transaction',
      testExplainTransaction(EosInputs.explainTransactionInputNative, EosResponses.explainTransactionOutputNative)
    );
    it(
      'explains CHEX token transfer transaction',
      testExplainTransaction(EosInputs.explainTransactionInputChex, EosResponses.explainTransactionOutputChex)
    );
    it(
      'explain EOS Unstake1 transaction',
      testExplainTransaction(EosInputs.explainUnstakeInput1, EosResponses.explainUnstakeOutput1)
    );
    it(
      'explain EOS Unstake2 transaction',
      testExplainTransaction(EosInputs.explainUnstakeInput2, EosResponses.explainUnstakeOutput2)
    );
    it(
      'explain EOS Refund transaction',
      testExplainTransaction(EosInputs.explainRefundInput, EosResponses.explainRefundOutput)
    );
  });

  describe('Transaction Verification', function () {
    let wallet;
    let basecoin;
    let verification;
    let sandBox;
    let newTxPrebuild;
    let newTxParams;

    before(async () => {
      basecoin = bitgo.coin('teos');
      const walletData = {
        id: '5a78dd561c6258a907f1eeaee132f796',
        users: [
          {
            user: '543c11ed356d00cb7600000b98794503',
            permissions: ['admin', 'view', 'spend'],
          },
        ],
        coin: 'teos',
        label: 'Verification Wallet',
        m: 2,
        n: 3,
        keys: [
          '5a78dd56bfe424aa07aa068651b194fd',
          '5a78dd5674a70eb4079f58797dfe2f5e',
          '5a78dd561c6258a907f1eea9f1d079e2',
        ],
        tags: ['5a78dd561c6258a907f1eeaee132f796'],
        disableTransactionNotifications: false,
        freeze: {},
        deleted: false,
        approvalsRequired: 1,
        isCold: true,
        coinSpecific: {},
        clientFlags: [],
        balance: 650000000,
        confirmedBalance: 650000000,
        spendableBalance: 650000000,
        balanceString: '650000000',
        confirmedBalanceString: '650000000',
        spendableBalanceString: '650000000',
        receiveAddress: {
          id: '5a78de2bbfe424aa07aa131ec03c8dc1',
          address: '78xczhaijyhek2',
          chain: 0,
          index: 0,
          coin: 'teos',
          wallet: '5a78dd561c6258a907f1eeaee132f796',
          coinSpecific: {},
        },
        pendingApprovals: [],
      };
      wallet = new Wallet(bitgo, basecoin, walletData);
      const userKeychain = {
        prv: '5KJq565HTrgEJG9EbvJH5BLYTgioAyY27dT9am1kCtn2YVAJEYK',
        pub: 'EOS6g7AAMQkhXp8j73E8BD4KRwtQevEsFgYx8htaQkRVhhXJMgkMZ',
      };
      const backupKeychain = {
        prv: '5KZ1nXXCi5yXH8AjCJqjnCYHCVnhQa9YWGV2D14i8g221dxNwLW',
        pub: 'EOS7gyDLNk12faVb1aqNxj1L2DpBerFkhAsxBs95yW3yxJpqvg9Mt',
      };
      const txPrebuild = {
        recipients: [
          {
            address: 'lionteste212',
            amount: '1000',
          },
        ],
        headers: {
          expiration: '2021-10-28T02:34:05.848',
          ref_block_num: 42915,
          ref_block_prefix: 1204086709,
        },
        txHex:
          '2a02a0053e5a8cf73a56ba0fda11e4d92e0238a4a2aa74fccf46d5a9107468401e0c7a61a3a7b5e7c4470000000100408c7a02ea3055000000000085269d00030233330100a6823403ea3055000000572d3ccdcd0120ceb8437333427c00000000a8ed32322220ceb8437333427c20825019ab3ca98be80300000000000004454f53000000000131000000000000000000000000000000000000000000000000000000000000000000',
        transaction: {
          compression: 'none',
          packed_trx:
            '1e0c7a61a3a7b5e7c4470000000100408c7a02ea3055000000000085269d00030233330100a6823403ea3055000000572d3ccdcd0120ceb8437333427c00000000a8ed32322220ceb8437333427c20825019ab3ca98be80300000000000004454f5300000000013100',
          signatures: [],
        },
        txid: '586c5b59b10b134d04c16ac1b273fe3c5529f34aef75db4456cd469c5cdac7e2',
        isVotingTransaction: false,
        coin: 'teos',
      };
      verification = {
        disableNetworking: true,
        keychains: {
          user: { pub: userKeychain.pub },
          backup: { pub: backupKeychain.pub },
        },
      };
      const seed = Buffer.from('c3b09c24731be2851b624d9d5b3f60fa129695c24071768d15654bea207b7bb6', 'hex');
      const keyPair = basecoin.generateKeyPair(seed);
      const txParams = {
        txPrebuild,
        prv: keyPair.prv,
        recipients: [
          {
            address: 'lionteste212?memoId=1',
            amount: '1000',
          },
        ],
      };

      newTxPrebuild = () => {
        return _.cloneDeep(txPrebuild);
      };
      newTxParams = () => {
        return _.cloneDeep(txParams);
      };
    });

    beforeEach(async () => {
      // mock responses to the block chain
      sandBox = sinon.createSandbox();
      const callBack = sandBox.stub(Eos.prototype, <any>'getDataFromNode');
      callBack
        .withArgs({
          endpoint: '/v1/chain/get_info',
        })
        .resolves(EosResponses.getInfoResponseSuccess1);
      callBack
        .withArgs({
          endpoint: '/v1/chain/get_block',
          payload: { block_num_or_id: 191839472 },
        })
        .resolves(EosResponses.getBlockResponseSuccess1);
    });

    afterEach(async () => {
      sandBox.restore();
    });

    it('should verify a transaction', async function () {
      const txParams = newTxParams();
      const txPrebuild = newTxPrebuild();
      const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification });
      validTransaction.should.equal(true);
    });

    it('should verify a transaction without a memoId', async function () {
      const txPrebuild = newTxPrebuild();

      // txParams with different txPrebuild
      const txPrebuild2 = newTxPrebuild();
      txPrebuild2.recipients[0].address = 'lionteste212';
      const txParams = newTxParams();
      txParams.txPrebuild = txPrebuild2;

      const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification });
      validTransaction.should.equal(true);
    });

    it('should throw if different prebuilds are provided in txParams and txPrebuild', async function () {
      const txPrebuild = newTxPrebuild();

      // txParams with different txPrebuild
      const txPrebuild2 = newTxPrebuild();
      txPrebuild2.recipients[0].address = 'sadjghaslsdgo';
      const txParams = newTxParams();
      txParams.txPrebuild = txPrebuild2;

      await basecoin
        .verifyTransaction({ txParams, txPrebuild, wallet, verification })
        .should.be.rejectedWith('inputs txParams.txPrebuild and txPrebuild expected to be equal but were not');
    });

    it('should throw if unpacked txHex is not the same as the unpacked packed_trx', async function () {
      const txPrebuild = newTxPrebuild();
      txPrebuild.txHex =
        'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf9111111111111111111111111111111111640000000000000100408c7a02ea3055000000000085269d000201310100a6823403ea3055000000572d3ccdcd01d0f9ce64f437f7cf00000000a8ed323222d0f9ce64f437f7cfb012362b61b31236640000000000000004454f53000000000131000000000000000000000000000000000000000000000000000000000000000000';
      const txParams = newTxParams();
      txParams.txPrebuild = txPrebuild;
      await basecoin
        .verifyTransaction({ txParams, txPrebuild, wallet, verification })
        .should.be.rejectedWith('unpacked packed_trx and unpacked txHex are not equal');
    });

    it('should throw if the expected amount is different than actual amount', async function () {
      const txPrebuild = newTxPrebuild();
      const txParams = newTxParams();
      txParams.recipients[0].amount = 10000;
      await basecoin
        .verifyTransaction({ txParams, txPrebuild, wallet, verification })
        .should.be.rejectedWith('txHex receive amount does not match expected recipient amount');
    });

    it('should throw if the expected recipient is different than actual recipient', async function () {
      const txPrebuild = newTxPrebuild();
      const txParams = newTxParams();
      txParams.recipients[0].address = 'aaaaaaaaaaaa';
      await basecoin
        .verifyTransaction({ txParams, txPrebuild, wallet, verification })
        .should.be.rejectedWith('txHex receive address does not match expected recipient address');
    });

    it('should throw if the expected memo is different than actual memo', async function () {
      const txPrebuild = newTxPrebuild();
      const txParams = newTxParams();
      txParams.recipients[0].address = 'lionteste212?memoId=10';
      await basecoin
        .verifyTransaction({ txParams, txPrebuild, wallet, verification })
        .should.be.rejectedWith('txHex receive memoId does not match expected recipient memoId');
    });

    it('should verify transaction with memo id in params only', async function () {
      const txPrebuild = newTxPrebuild();

      txPrebuild.headers = {
        expiration: '2021-11-08T17:24:47.792',
        ref_block_num: 1,
        ref_block_prefix: 100,
      };
      // has memoid in the txaction with value of '1'
      txPrebuild.txHex =
        'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473605d89610100640000000000000100408c7a02ea3055000000000085269d000201300100a6823403ea3055000000572d3ccdcd01001dd9f9a000a53d00000000a8ed323222001dd9f9a000a53d20825019ab3ca98be80300000000000004454f53000000000131000000000000000000000000000000000000000000000000000000000000000000';
      txPrebuild.transaction.packed_trx =
        '605d89610100640000000000000100408c7a02ea3055000000000085269d000201300100a6823403ea3055000000572d3ccdcd01001dd9f9a000a53d00000000a8ed323222001dd9f9a000a53d20825019ab3ca98be80300000000000004454f5300000000013100';
      const txParams = newTxParams();
      txParams.recipients[0].address = 'lionteste212';
      txParams.txPrebuild = txPrebuild;

      const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification });
      validTransaction.should.equal(true);
    });

    it('should verify transaction with alpha numeric memo id params', async function () {
      const txPrebuild = newTxPrebuild();

      txPrebuild.headers = {
        expiration: '2021-11-08T17:55:17.518',
        ref_block_num: 1,
        ref_block_prefix: 100,
      };
      // has memoid in the txaction with value of 'QG73WAXXG'
      txPrebuild.txHex =
        'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473866489610100640000000000000100408c7a02ea3055000000000085269d000201300100a6823403ea3055000000572d3ccdcd013085b943b1b54ed700000000a8ed32322a3085b943b1b54ed720825019ab3ca98be80300000000000004454f530000000009514737335741585847000000000000000000000000000000000000000000000000000000000000000000';
      txPrebuild.transaction.packed_trx =
        '866489610100640000000000000100408c7a02ea3055000000000085269d000201300100a6823403ea3055000000572d3ccdcd013085b943b1b54ed700000000a8ed32322a3085b943b1b54ed720825019ab3ca98be80300000000000004454f53000000000951473733574158584700';
      const txParams = newTxParams();
      txParams.recipients[0].address = 'lionteste212';
      txParams.txPrebuild = txPrebuild;

      const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild, wallet, verification });
      validTransaction.should.equal(true);
    });
  });
});

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


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