PHP WebShell

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

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

import * as CsprAccountLib from '../../src/lib';
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
import { Cspr, ExplainTransactionOptions, TransactionFee } from '../../src/cspr';
import { Tcspr } from '../../src/tcspr';
import { randomBytes } from 'crypto';
import * as should from 'should';
import { signedRawDelegateTx, signedRawTransferTx, signedRawUndelegateTx } from '../fixtures/cspr';
import { TransactionType } from '@bitgo/sdk-core';
import { BitGoAPI } from '@bitgo/sdk-api';
import { coins } from '@bitgo/statics';
import assert from 'assert';

type Transaction = CsprAccountLib.Transaction;

describe('Casper', function () {
  const coinName = 'tcspr';
  let bitgo: TestBitGoAPI;
  let basecoin;

  before(function () {
    bitgo = TestBitGo.decorate(BitGoAPI, {
      env: 'mock',
    });
    bitgo.initializeTestVars();
    bitgo.safeRegister('cspr', Cspr.createInstance);
    bitgo.safeRegister('tcspr', Tcspr.createInstance);
    basecoin = bitgo.coin(coinName);
  });

  it('should instantiate the coin', function () {
    let localBasecoin = bitgo.coin('tcspr');
    localBasecoin.should.be.an.instanceof(Tcspr);

    localBasecoin = bitgo.coin('cspr');
    localBasecoin.should.be.an.instanceof(Cspr);
  });

  it('should return tcspr', function () {
    basecoin.getChain().should.equal('tcspr');
  });

  it('should return full name', function () {
    basecoin.getFullName().should.equal('Testnet Casper');
  });

  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');
    });

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

      keyPair.pub.should.equal(
        'xpub661MyMwAqRbcFnJi3mvSpYNYyXUcjq7spqHg9GhpcWqs3wF4S8forUeJ3K8XfpUumpY4mLhaGPWAxAJETCnJM56w5f25g6kvLh5Bxb3ZEbD'
      );
      keyPair.prv.should.equal(
        'xprv9s21ZrQH143K3JEEwkPSTQRpRVe8LNQ2TcN5LtJD4BJtB8uutbMZJgKpC3EPHMPGn97Y9aXFYeFegFsPdZXu6BF5XB7yXhZDUE5d6keTHyV'
      );
    });

    it('should validate a public key', function () {
      const keyPair = basecoin.generateKeyPair();
      keyPair.should.have.property('pub');
      keyPair.should.have.property('prv');

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

    it('should validate a private key', function () {
      const keyPair = basecoin.generateKeyPair();
      keyPair.should.have.property('pub');
      keyPair.should.have.property('prv');

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

    it('Should supplement wallet generation', async function () {
      const details = await basecoin.supplementGenerateWallet({});
      details.should.have.property('rootPrivateKey');
      basecoin.isValidPrv(details.rootPrivateKey).should.equal(true);
    });

    it('Should supplement wallet generation with provided private key', async function () {
      const rootPrivateKey = 'e0c5c347fc67a46aa5104ece454882315fe5d70af286dbd3d2e04227ebd2927d';
      const details = await basecoin.supplementGenerateWallet({ rootPrivateKey });
      details.should.have.property('rootPrivateKey');
      details.rootPrivateKey.should.equal(rootPrivateKey);
    });
  });

  describe('Sign Transaction', () => {
    const factory = new CsprAccountLib.TransactionBuilderFactory(coins.get(coinName));
    const sourceKeyPairObject = new CsprAccountLib.KeyPair();
    const sourceKeyPair = sourceKeyPairObject.getKeys();
    const targetKeyPairObject = new CsprAccountLib.KeyPair();
    const extendedSourceKeyPair = sourceKeyPairObject.getExtendedKeys();

    it('should be performed', async () => {
      const bitgoKeyPairObject = new CsprAccountLib.KeyPair();
      const bitgoKeyPair = bitgoKeyPairObject.getKeys();
      const builder = factory.getTransferBuilder();
      builder
        .fee({ gasLimit: '10000', gasPrice: '10' })
        .source({ address: sourceKeyPairObject.getAddress() })
        .to(targetKeyPairObject.getAddress())
        .amount('2500000000')
        .transferId(123);

      const tx = (await builder.build()) as Transaction;
      tx.casperTx.approvals.length.should.equals(0);

      const params = {
        txPrebuild: {
          txHex: tx.toBroadcastFormat(),
        },
        prv: sourceKeyPair.prv,
      };

      let signedTransaction = await basecoin.signTransaction(params);
      signedTransaction.should.have.property('halfSigned');

      const halfSignedTx = JSON.parse(signedTransaction.halfSigned.txHex);
      halfSignedTx.deploy.approvals.length.should.equals(1);
      halfSignedTx.deploy.approvals[0].signer
        .toUpperCase()
        .should.equals(sourceKeyPairObject.getAddress().toUpperCase());
      CsprAccountLib.Utils.isValidTransactionSignature(
        halfSignedTx.deploy.approvals[0].signature,
        halfSignedTx.deploy.hash,
        sourceKeyPair.pub
      ).should.equals(true);

      params.txPrebuild.txHex = signedTransaction.halfSigned.txHex;
      params.prv = bitgoKeyPair.prv;
      signedTransaction = await basecoin.signTransaction(params);
      signedTransaction.should.not.have.property('halfSigned');
      signedTransaction.should.have.property('txHex');

      const twiceSignedTx = JSON.parse(signedTransaction.txHex);
      twiceSignedTx.deploy.approvals.length.should.equals(2);
      twiceSignedTx.deploy.approvals[0].signer
        .toUpperCase()
        .should.equals(sourceKeyPairObject.getAddress().toUpperCase());
      twiceSignedTx.deploy.approvals[1].signer
        .toUpperCase()
        .should.equals(bitgoKeyPairObject.getAddress().toUpperCase());

      CsprAccountLib.Utils.isValidTransactionSignature(
        twiceSignedTx.deploy.approvals[0].signature,
        twiceSignedTx.deploy.hash,
        sourceKeyPair.pub
      ).should.equals(true);
      CsprAccountLib.Utils.isValidTransactionSignature(
        twiceSignedTx.deploy.approvals[1].signature,
        twiceSignedTx.deploy.hash,
        bitgoKeyPair.pub
      ).should.equals(true);
    });

    it('should be performed with extended keys', async () => {
      const bitgoKeyPairObject = new CsprAccountLib.KeyPair();
      const bitgoKeyPair = bitgoKeyPairObject.getKeys();
      const extendedBitgoKeyPair = bitgoKeyPairObject.getExtendedKeys();

      const builder = factory.getTransferBuilder();
      builder
        .fee({ gasLimit: '10000', gasPrice: '10' })
        .source({ address: sourceKeyPairObject.getAddress() })
        .to(targetKeyPairObject.getAddress())
        .amount('2500000000')
        .transferId(123);

      const tx = (await builder.build()) as Transaction;
      tx.casperTx.approvals.length.should.equals(0);

      const params = {
        txPrebuild: {
          txHex: tx.toBroadcastFormat(),
        },
        prv: extendedSourceKeyPair.xprv,
      };

      let signedTransaction = await basecoin.signTransaction(params);
      signedTransaction.should.have.property('halfSigned');

      const halfSignedTx = JSON.parse(signedTransaction.halfSigned.txHex);
      halfSignedTx.deploy.approvals.length.should.equals(1);
      halfSignedTx.deploy.approvals[0].signer
        .toUpperCase()
        .should.equals(sourceKeyPairObject.getAddress().toUpperCase());
      CsprAccountLib.Utils.isValidTransactionSignature(
        halfSignedTx.deploy.approvals[0].signature,
        halfSignedTx.deploy.hash,
        sourceKeyPair.pub
      ).should.equals(true);

      params.txPrebuild.txHex = signedTransaction.halfSigned.txHex;
      params.prv = extendedBitgoKeyPair.xprv;
      signedTransaction = await basecoin.signTransaction(params);
      signedTransaction.should.not.have.property('halfSigned');
      signedTransaction.should.have.property('txHex');

      const twiceSignedTxHex = JSON.parse(signedTransaction.txHex);
      twiceSignedTxHex.deploy.approvals.length.should.equals(2);
      twiceSignedTxHex.deploy.approvals[0].signer
        .toUpperCase()
        .should.equals(sourceKeyPairObject.getAddress().toUpperCase());
      twiceSignedTxHex.deploy.approvals[1].signer
        .toUpperCase()
        .should.equals(bitgoKeyPairObject.getAddress().toUpperCase());

      CsprAccountLib.Utils.isValidTransactionSignature(
        twiceSignedTxHex.deploy.approvals[0].signature,
        twiceSignedTxHex.deploy.hash,
        sourceKeyPair.pub
      ).should.equals(true);
      CsprAccountLib.Utils.isValidTransactionSignature(
        twiceSignedTxHex.deploy.approvals[1].signature,
        twiceSignedTxHex.deploy.hash,
        bitgoKeyPair.pub
      ).should.equals(true);
    });

    it('should be rejected if invalid key', async () => {
      const sourceKeyPairObject = new CsprAccountLib.KeyPair();
      const targetKeyPairObject = new CsprAccountLib.KeyPair();
      const invalidPrivateKey = 'AAAAA';
      const builder = factory.getTransferBuilder();
      builder
        .fee({ gasLimit: '10000', gasPrice: '10' })
        .source({ address: sourceKeyPairObject.getAddress() })
        .to(targetKeyPairObject.getAddress())
        .amount('2500000000')
        .transferId(123);

      const tx = (await builder.build()) as Transaction;
      tx.casperTx.approvals.length.should.equals(0);

      const params = {
        txPrebuild: {
          txHex: tx.toBroadcastFormat(),
        },
        prv: invalidPrivateKey,
      };

      await basecoin.signTransaction(params).should.be.rejected();
    });
  });

  describe('Sign Message', () => {
    it('should be performed', async () => {
      const keyPair = new CsprAccountLib.KeyPair().getKeys();
      const messageToSign = Buffer.from(randomBytes(32)).toString('hex');
      const signature = await basecoin.signMessage(keyPair, messageToSign);
      CsprAccountLib.Utils.isValidMessageSignature(signature.toString('hex'), messageToSign, keyPair.pub).should.equals(
        true
      );
    });

    it('should be performed with extended keys', async () => {
      const keyPairToSign = new CsprAccountLib.KeyPair();
      const keyPairExtendedKeys = keyPairToSign.getExtendedKeys();
      const keyPair = keyPairToSign.getKeys();
      const messageToSign = Buffer.from(randomBytes(32)).toString('hex');
      const signature = await basecoin.signMessage(
        { pub: keyPairExtendedKeys.xpub, prv: keyPairExtendedKeys.xprv },
        messageToSign
      );
      CsprAccountLib.Utils.isValidMessageSignature(signature.toString('hex'), messageToSign, keyPair.pub).should.equals(
        true
      );
    });

    it('should fail with missing private key', async () => {
      const keyPair = new CsprAccountLib.KeyPair({
        pub: '029F697A02355839A02157E87721F7C44EE45DE9B891266BE065FD7F9B4EB31B88',
      }).getKeys();
      const messageToSign = Buffer.from(randomBytes(32)).toString('hex');
      basecoin.signMessage(keyPair, messageToSign).should.be.rejectedWith('Invalid key pair options');
    });
  });

  describe('Explain Transaction', () => {
    const factory = new CsprAccountLib.TransactionBuilderFactory(coins.get(coinName));
    const sourceKeyPairObject = new CsprAccountLib.KeyPair();
    const sourceKeyPair = sourceKeyPairObject.getKeys();
    const targetKeyPairObject = new CsprAccountLib.KeyPair();
    let txBuilder;
    let dgBuilder;
    let udgBuilder;
    const transferAmount = '2500000000';
    const delegateAmount = '250000000';
    const undelegateAmount = '250000000';
    const transferId = 123;

    before(function () {
      txBuilder = factory.getTransferBuilder();
      txBuilder
        .fee({ gasLimit: '10000', gasPrice: '10' })
        .source({ address: sourceKeyPairObject.getAddress() })
        .to(targetKeyPairObject.getAddress())
        .amount(transferAmount)
        .transferId(transferId);

      dgBuilder = factory.getDelegateBuilder();
      dgBuilder
        .fee({ gasLimit: '3000000000', gasPrice: '1' })
        .source({ address: sourceKeyPairObject.getAddress() })
        .amount(delegateAmount)
        .validator('0115c9b40c06ff99b0cbadf1140b061b5dbf92103e66a6330fbcc7768f5219c1ce');

      udgBuilder = factory.getUndelegateBuilder();
      udgBuilder
        .fee({ gasLimit: '3000000000', gasPrice: '1' })
        .source({ address: sourceKeyPairObject.getAddress() })
        .amount(undelegateAmount)
        .validator('0115c9b40c06ff99b0cbadf1140b061b5dbf92103e66a6330fbcc7768f5219c1ce');
    });

    it('should explain a half signed transfer transaction', async () => {
      const tx = (await txBuilder.build()) as Transaction;
      const signTxparams = {
        txPrebuild: {
          txHex: tx.toBroadcastFormat(),
        },
        prv: sourceKeyPair.prv,
      };
      const { halfSigned } = await basecoin.signTransaction(signTxparams);

      const feeInfo: TransactionFee = {
        gasLimit: '1',
        gasPrice: '11000',
      };
      const explainTxParams: ExplainTransactionOptions = {
        halfSigned: {
          txHex: halfSigned.txHex,
        },
        feeInfo,
      };
      const explainedTx = await basecoin.explainTransaction(explainTxParams);
      explainedTx.should.have.properties([
        'displayOrder',
        'id',
        'outputs',
        'outputAmount',
        'transferId',
        'fee',
        'changeOutputs',
        'changeAmount',
      ]);
      explainedTx.fee.should.equal(feeInfo);
      explainedTx.outputs.length.should.equal(1);
      explainedTx.outputs.forEach((output) => {
        output.amount.should.equal(transferAmount);
        output.address.should.equal(targetKeyPairObject.getAddress());
        output.coin.should.equal(basecoin.getChain());
      });
      explainedTx.outputAmount.should.equal(transferAmount);
      explainedTx.transferId.should.equal(transferId.toString());
    });

    it('should explain a signed transfer transaction', async () => {
      const builtTxInfo = {
        txHex: signedRawTransferTx,
        txInfo: {
          hash: 'cf7eac1a10f350f393163c8254770649b953dcd3cf8e180aaba463816fbd0a0b',
          fee: {
            gasLimit: '11000',
            gasPrice: '1',
          },
          from: '02cc8f78c41d334ad2aaae6da7a88537f9686245761aaddf36d4b2dfbf913bb873',
          startTime: '2021-12-14T00:53:32.836Z',
          expiration: 7200000,
          deployType: 'Send',
          to: '0202227faa327bb6607f1b6245d275b0c9aef32db568986b5252323fd498923f1ef1',
          amount: '2500000000',
          transferId: '123',
        },
        feeInfo: {
          gasLimit: '11000',
          gasPrice: '1',
        },
        recipients: [
          {
            address: '0202fba9e5705a8860fc1b5563b981a4c2c94af03fc10916eb7819b183056c43d3b0',
            amount: '2500000000',
          },
        ],
      };
      const explainTxParams: ExplainTransactionOptions = builtTxInfo;
      const explainedTx = await basecoin.explainTransaction(explainTxParams);
      explainedTx.should.have.properties([
        'displayOrder',
        'id',
        'outputs',
        'outputAmount',
        'transferId',
        'fee',
        'changeOutputs',
        'changeAmount',
      ]);
      explainedTx.fee.should.equal(builtTxInfo.feeInfo);
      explainedTx.id.should.equal(builtTxInfo.txInfo.hash);
      explainedTx.outputs.length.should.equal(1);
      explainedTx.outputs[0].amount.should.equal(builtTxInfo.txInfo.amount);
      explainedTx.outputs[0].address.should.equal(builtTxInfo.txInfo.to);
      explainedTx.outputs[0].coin.should.equal(basecoin.getChain());
      explainedTx.outputAmount.should.equal(builtTxInfo.txInfo.amount);
      explainedTx.transferId.should.equal(builtTxInfo.txInfo.transferId);
    });

    it('should explain a half signed delegate transaction', async () => {
      const tx = (await dgBuilder.build()) as Transaction;
      const signTxparams = {
        txPrebuild: {
          txHex: tx.toBroadcastFormat(),
        },
        prv: sourceKeyPair.prv,
      };
      const { halfSigned } = await basecoin.signTransaction(signTxparams);

      const feeInfo: TransactionFee = {
        gasLimit: '1',
        gasPrice: '3000000000',
      };
      const explainTxParams: ExplainTransactionOptions = {
        halfSigned: {
          txHex: halfSigned.txHex,
        },
        feeInfo,
      };
      const txInfo = {
        hash: 'b47ca168a2c6ec864c5923a98bb8bca8cb78f0141bdeb37f9ad74705f8c40636',
        fee: {
          gasLimit: '3000000000',
          gasPrice: '1',
        },
        from: '0202cc8f78c41d334ad2aaae6da7a88537f9686245761aaddf36d4b2dfbf913bb873',
        deployType: TransactionType.StakingLock,
        amount: delegateAmount,
        validator: '0115c9b40c06ff99b0cbadf1140b061b5dbf92103e66a6330fbcc7768f5219c1ce',
      };
      const explainedTx = await basecoin.explainTransaction(explainTxParams);
      explainedTx.should.have.properties([
        'displayOrder',
        'id',
        'outputs',
        'outputAmount',
        'transferId',
        'fee',
        'changeOutputs',
        'changeAmount',
        'operations',
      ]);
      explainedTx.fee.should.equal(explainTxParams.feeInfo);
      explainedTx.outputs.length.should.equal(0);
      explainedTx.operations.length.should.equal(1);
      explainedTx.operations[0].amount.should.equal(txInfo.amount);
      explainedTx.operations[0].validator.should.equal(txInfo.validator);
      explainedTx.operations[0].coin.should.equal(basecoin.getChain());
      explainedTx.operations[0].type.should.equal(txInfo.deployType);
    });

    it('should explain a signed delegate transaction', async () => {
      const builtTxInfo = {
        txHex: signedRawDelegateTx,
        txInfo: {
          hash: '771a192224097faf0f1b18295a50e4bf190728cf365711b030cb083d0785e993',
          fee: {
            gasLimit: '100000000',
            gasPrice: '1',
          },
          from: '0202cc8f78c41d334ad2aaae6da7a88537f9686245761aaddf36d4b2dfbf913bb873',
          deployType: TransactionType.StakingLock,
          amount: delegateAmount,
          validator: '0115c9b40c06ff99b0cbadf1140b061b5dbf92103e66a6330fbcc7768f5219c1ce',
        },
        feeInfo: {
          gasLimit: '100000000',
          gasPrice: '1',
        },
      };
      const explainTxParams: ExplainTransactionOptions = builtTxInfo;
      const explainedTx = await basecoin.explainTransaction(explainTxParams);
      explainedTx.should.have.properties([
        'displayOrder',
        'id',
        'outputs',
        'outputAmount',
        'transferId',
        'fee',
        'changeOutputs',
        'changeAmount',
        'operations',
      ]);
      explainedTx.fee.should.equal(builtTxInfo.feeInfo);
      explainedTx.outputs.length.should.equal(0);
      explainedTx.operations.length.should.equal(1);
      explainedTx.operations[0].amount.should.equal(builtTxInfo.txInfo.amount);
      explainedTx.operations[0].validator.should.equal(builtTxInfo.txInfo.validator);
      explainedTx.operations[0].coin.should.equal(basecoin.getChain());
      explainedTx.operations[0].type.should.equal(builtTxInfo.txInfo.deployType);
    });

    it('should explain a half signed undelegate transaction', async () => {
      const tx = (await udgBuilder.build()) as Transaction;
      const signTxparams = {
        txPrebuild: {
          txHex: tx.toBroadcastFormat(),
        },
        prv: sourceKeyPair.prv,
      };
      const { halfSigned } = await basecoin.signTransaction(signTxparams);

      const feeInfo: TransactionFee = {
        gasLimit: '1',
        gasPrice: '3000000000',
      };
      const explainTxParams: ExplainTransactionOptions = {
        halfSigned: {
          txHex: halfSigned.txHex,
        },
        feeInfo,
      };
      const txInfo = {
        hash: 'b47ca168a2c6ec864c5923a98bb8bca8cb78f0141bdeb37f9ad74705f8c40636',
        fee: {
          gasLimit: '3000000000',
          gasPrice: '1',
        },
        from: '0202cc8f78c41d334ad2aaae6da7a88537f9686245761aaddf36d4b2dfbf913bb873',
        deployType: TransactionType.StakingUnlock,
        amount: undelegateAmount,
        validator: '0115c9b40c06ff99b0cbadf1140b061b5dbf92103e66a6330fbcc7768f5219c1ce',
      };
      const explainedTx = await basecoin.explainTransaction(explainTxParams);
      explainedTx.should.have.properties([
        'displayOrder',
        'id',
        'outputs',
        'outputAmount',
        'transferId',
        'fee',
        'changeOutputs',
        'changeAmount',
        'operations',
      ]);
      explainedTx.fee.should.equal(explainTxParams.feeInfo);
      explainedTx.outputs.length.should.equal(0);
      explainedTx.operations.length.should.equal(1);
      explainedTx.operations[0].amount.should.equal(txInfo.amount);
      explainedTx.operations[0].validator.should.equal(txInfo.validator);
      explainedTx.operations[0].coin.should.equal(basecoin.getChain());
      explainedTx.operations[0].type.should.equal(txInfo.deployType);
    });

    it('should explain a signed undelegate transaction', async () => {
      const builtTxInfo = {
        txHex: signedRawUndelegateTx,
        txInfo: {
          hash: 'aead2e9e9a43e3d545908e1b995628cb9c37e712d7467b63c052fe63bed8cf17',
          fee: {
            gasLimit: '100000000',
            gasPrice: '1',
          },
          from: '0202cc8f78c41d334ad2aaae6da7a88537f9686245761aaddf36d4b2dfbf913bb873',
          deployType: TransactionType.StakingUnlock,
          amount: undelegateAmount,
          validator: '0115c9b40c06ff99b0cbadf1140b061b5dbf92103e66a6330fbcc7768f5219c1ce',
        },
        feeInfo: {
          gasLimit: '100000000',
          gasPrice: '1',
        },
      };
      const explainTxParams: ExplainTransactionOptions = builtTxInfo;
      const explainedTx = await basecoin.explainTransaction(explainTxParams);
      explainedTx.should.have.properties([
        'displayOrder',
        'id',
        'outputs',
        'outputAmount',
        'transferId',
        'fee',
        'changeOutputs',
        'changeAmount',
        'operations',
      ]);
      explainedTx.fee.should.equal(builtTxInfo.feeInfo);
      explainedTx.outputs.length.should.equal(0);
      explainedTx.operations.length.should.equal(1);
      explainedTx.operations[0].amount.should.equal(builtTxInfo.txInfo.amount);
      explainedTx.operations[0].validator.should.equal(builtTxInfo.txInfo.validator);
      explainedTx.operations[0].coin.should.equal(basecoin.getChain());
      explainedTx.operations[0].type.should.equal(builtTxInfo.txInfo.deployType);
    });

    it('should fail when a tx is not passed as parameter', async () => {
      const explainTxParams = {
        fee: {
          gasLimit: '1',
          gasPrice: '11000',
        },
      };
      await basecoin.explainTransaction(explainTxParams).should.be.rejectedWith('missing explain tx parameters');
    });
  });

  describe('Validation', function () {
    it('should fail to validate invalid address with payment id', function () {
      const invalidAddresses = [
        '0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?transferId=x',
        '0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?memoId=1',
        'X0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?transferId=1',
      ];

      for (const address of invalidAddresses) {
        should.doesNotThrow(() => basecoin.isValidAddress(address));
        basecoin.isValidAddress(address).should.be.false();
      }
    });

    it('should validate address with payment id', function () {
      const validAddresses = [
        '0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?transferId=0',
        '020385D724A9A3E7E32BADF40F3279AF5A190CB2CFCAB6639BF532A0069E0E3824D0?transferId=1',
        '01513fa90c1a74c34a8958dd86055e9736edb1ead918bd4d4d750ca851946be7aa?transferId=999999999', // ed25519
      ];

      for (const address of validAddresses) {
        basecoin.isValidAddress(address).should.be.true();
      }
    });

    it('should fail to verify invalid address with payment id', async function () {
      const invalidAddresses = [
        '0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?transferId=x',
        '0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?memoId=1',
        'X0203DC13CBBF29765C7745578D9E091280522F37684EF0E400B86B1C409BC454F1F3?transferId=1',
      ];

      for (const address of invalidAddresses) {
        await assert.rejects(async () => basecoin.verifyAddress(address));
      }
    });

    it('should verify address with payment id', async function () {
      const rootAddress = '020250fe213706e46aaa32cb23f0705833c6d3ce7652e8e5a1349dde102aadf014b7';
      const keychains = [
        {
          id: '624f0dcc93cbcc0008d88df2369a565e',
          pub: 'xpub661MyMwAqRbcEeRkBciuaUfF4C1jgBcnj2RXdnt9gokx4CFRBUp4bsbk5hXHC1BrBDZLDNecVsUCMmoLpPhWdPZhPiTsHSoxNoGVW9KtiEQ',
          ethAddress: '0xcfbf38770af3a95da7998537a481434e2cb9b2fa',
          source: 'user',
          type: 'independent',
          encryptedPrv:
            '{"iv":"Z2XySTRNipFZ06/EXynwvA==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"KGRPbZ2jt1g=","ct":"szpCbDLFIlRZvCBV60SWBEMYXvny7YlBtu4ffjlctDQGjR4/+vfCkovgGHs+Xvf/eIlUM3Kicubg+Sdp61MImjMT/umZ3IJT1E2I9mM0QDqpzXlohTGnJ4vgfHgCz3QkB4uYm5mqaD4LtRbvZbGhGrc5jzrLzqQ="}',
        },
        {
          id: '624f0dcd93cbcc0008d88e0fc4261a38',
          pub: 'xpub661MyMwAqRbcGeqZVFgQfcD8zLoxaZL7y4cVAjhE8ybMTpvbppP6rc22a69BgcNVo74yL8fWPzNM5vAozBE7chzGYoPDJMyJ39F2HeAsGcn',
          ethAddress: '0xbf37f39208d77e3254b7efbcab1432b9c353e337',
          source: 'backup',
          type: 'independent',
          encryptedPrv:
            '{"iv":"T9gdJnSAEWFsLZ4cg9VA8g==","v":1,"iter":10000,"ks":256,"ts":64,"mode":"ccm","adata":"","cipher":"aes","salt":"FaLlns3mPiI=","ct":"QW5Zq9qJoDxDrK60zTAM6Lg+S4KP9FcEn9AHw5UIyakSBlD0XjVTluZ9PlTABjIlp9cQvMef/SH8Em1d4ash0PACoqBz2IxPwhW9h6uyQBdqk97iPrnM2rOQobsy9p0ILJM10fOgB+EEFYX5yQ5gyfEcK060j/Q="}',
        },
        {
          id: '624f0dce10610a0007fc5282353187ae',
          pub: 'xpub661MyMwAqRbcFVMAYJe51sgXaiFLeUb1v4u3B63CgBNMmMjtWBo32AS3bunsBUZMdi37pzovtEg5mVf6wBKayTYapGQRxymQjcmHaVmSPz8',
          ethAddress: '0x7527720b5638d2f5e2b272b20fc96d2223528d0e',
          source: 'bitgo',
          type: 'independent',
          isBitGo: true,
        },
      ];

      const validAddresses = [
        {
          address: '020250fe213706e46aaa32cb23f0705833c6d3ce7652e8e5a1349dde102aadf014b7',
          keychains,
          rootAddress,
        },
        {
          address: '020250FE213706E46AAA32CB23F0705833C6D3CE7652E8E5A1349DDE102AADF014B7?transferId=0',
          keychains,
          rootAddress,
        },
        {
          address: '020250fe213706e46aaa32cb23f0705833c6d3ce7652e8e5a1349dde102aadf014b7?transferId=5555',
          keychains,
          rootAddress,
        },
      ];

      for (const addressParams of validAddresses) {
        (await basecoin.verifyAddress(addressParams)).should.be.true();
      }
    });
  });

  describe('isWalletAddress', function () {
    const rootAddress = '0203d4c6ed4a40f5aa7371a73c79dd208a646ebc8c9f5c7fe0b4c73844365f0e62e5?transferId=4';

    it('should be valid', async function () {
      await basecoin
        .isWalletAddress({
          address: '0203d4c6ed4a40f5aa7371a73c79dd208a646ebc8c9f5c7fe0b4c73844365f0e62e5?transferId=5',
          rootAddress,
        })
        .should.be.resolvedWith(true);
      await basecoin
        .isWalletAddress({
          address: '0203d4c6ed4a40f5aa7371a73c79dd208a646ebc8c9f5c7fe0b4c73844365f0e62e5?transferId=500',
          rootAddress,
        })
        .should.be.resolvedWith(true);
      await basecoin
        .isWalletAddress({
          address: '0203d4c6ed4a40f5aa7371a73c79dd208a646ebc8c9f5c7fe0b4c73844365f0e62e5',
          rootAddress,
        })
        .should.be.resolvedWith(true);
      await basecoin
        .isWalletAddress({
          address: '0203d4c6ed4a40f5aa7371a73c79dd208a646ebc8c9f5c7fe0b4c73844365f0e62e5?transferId=1',
          rootAddress,
        })
        .should.be.resolvedWith(true);
    });

    it('should be invalid', async function () {
      await basecoin
        .isWalletAddress({
          address: '0203d4c6ed4a40f5aa7371a73c79dd208a646ebc8c9f5c7fe0b4c73844365f0e62e6',
          rootAddress,
        })
        .should.be.rejected();
    });
  });
});

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


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