PHP WebShell

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

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

import { TransactionType } from '@bitgo/sdk-core';
import assert from 'assert';
import should from 'should';
import {
  KeyPair,
  Transaction,
  TransferBuilder,
  Interface,
  BatchTransactionBuilder,
  StakingBuilder,
  UnstakeBuilder,
  WithdrawUnstakedBuilder,
} from '../../src';
import utils from '../../src/lib/utils';
import { rawTx, accounts, jsonTransactions } from '../resources';
import { buildTestConfig } from './transactionBuilder/base';
import { STAKING_DESTINATION } from '../../src/lib/transaction';

class StubTransaction extends Transaction {
  private _txJson: Interface.TxData;

  setTxJson(json: Interface.TxData) {
    this._txJson = json;
  }

  toJson(): Interface.TxData {
    if (this._txJson) {
      return this._txJson;
    }
    return super.toJson();
  }
}

describe('Dot Transaction', () => {
  let tx: StubTransaction;
  const config = buildTestConfig();
  const material = utils.getMaterial(config);

  beforeEach(() => {
    tx = new StubTransaction(config);
  });

  describe('empty transaction', () => {
    it('should throw empty transaction', () => {
      assert.throws(() => tx.toJson(), /Empty transaction/);
      assert.throws(() => tx.toBroadcastFormat(), /Empty transaction/);
    });

    it('should not sign', async () => {
      try {
        tx.sign(new KeyPair({ prv: accounts.account1.secretKey }));
      } catch (e) {
        should.equal(e.message, 'No transaction data to sign');
      }
    });
  });

  describe('sign transaction', () => {
    it('cannot sign - wrong account secret', () => {
      tx.sender(accounts.account1.address);
      should.deepEqual(tx.canSign({ key: accounts.account2.secretKey }), false);
    });

    it('can sign', () => {
      tx.sender(accounts.account2.address);
      should.deepEqual(tx.canSign({ key: accounts.account2.secretKey }), true);
    });

    it('can generate valid txHash from signed transaction', () => {
      const signedTx = rawTx.transfer.westendSigned2;
      const txHash = utils.getTxHash(signedTx);
      const expectedHash = '0x252e9b53c1d068c275ef4c9b5afcffb2df42859203be1305d148c0c1441a5b20';

      txHash.should.equal(expectedHash);
    });
  });

  describe('should build from raw unsigned tx', async () => {
    it('Transaction size validation', async () => {
      const builder = new TransferBuilder(config).material(material);
      builder.from(rawTx.transfer.unsigned);
      builder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
        .sender({ address: accounts.account1.address });
      const tx = (await builder.build()) as Transaction;
      should.deepEqual(tx.transactionSize(), rawTx.transfer.unsigned.length / 2);
    });

    it('Should rebuild different hex if keepAlive is true or false for transferAll txs', async () => {
      const keepAliveFalseBuilder = new TransferBuilder(config).material(material);
      keepAliveFalseBuilder.from(rawTx.transferAll.unsignedKeepAliveFalse);
      keepAliveFalseBuilder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
        .sender({ address: accounts.account1.address });
      const keepAliveFalseTx = (await keepAliveFalseBuilder.build()).toJson();

      const keepAliveTrueBuilder = new TransferBuilder(config).material(material);
      keepAliveTrueBuilder.from(rawTx.transferAll.unsignedKeepAliveTrue);
      keepAliveTrueBuilder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d')
        .sender({ address: accounts.account1.address });
      const keepAliveTrueTx = (await keepAliveTrueBuilder.build()).toJson();

      should.notEqual(keepAliveFalseTx.id, keepAliveTrueTx.id);
      should.notEqual(keepAliveFalseTx.keepAlive, keepAliveTrueTx.keepAlive);
    });
  });

  describe('Dot Explain Transaction', () => {
    // let tx: StubTransaction;
    const sender = accounts.account1;
    const receiver = accounts.account3;

    it('should explain a transfer transaction', async () => {
      const json = JSON.parse(jsonTransactions.transfer) as Interface.TxData;
      tx.setTxJson(json);
      tx.transactionType(TransactionType.Send);
      const explain = tx.explainTransaction();
      explain.id.should.equal('0xecb860905342cf985b39276a07d6e6696746de4623c07df863f69cba153f939a');
      explain.outputAmount.should.equal('1000000000000');
      explain.outputs[0].amount.should.equal('1000000000000');
      explain.outputs[0].address.should.equal(accounts.account2.address);
      explain.fee.fee.should.equal('0');
      explain.changeAmount.should.equal('0');
      explain.type.should.equal(TransactionType.Send);
    });

    it('should explain a proxy transfer transaction', async () => {
      const json = JSON.parse(jsonTransactions.proxyTransfer) as Interface.TxData;
      tx.setTxJson(json);
      tx.transactionType(TransactionType.Send);
      const explain = tx.explainTransaction();
      explain.outputAmount.should.equal('90034235235322');
      explain.outputs[0].amount.should.equal('90034235235322');
      explain.outputs[0].address.should.equal(accounts.account2.address);
      explain.fee.fee.should.equal('0');
      explain.changeAmount.should.equal('0');
      explain.type.should.equal(TransactionType.Send);
      explain.owner?.should.equal(sender.address);
      explain.forceProxyType?.should.equal('Any');
    });

    it('should explain a address initialization transaction', async () => {
      const json = JSON.parse(jsonTransactions.walletInitialization) as Interface.TxData;
      tx.setTxJson(json);
      tx.transactionType(TransactionType.AddressInitialization);
      const explain = tx.explainTransaction();
      explain.outputAmount.should.equal('0');
      explain.fee.fee.should.equal('0');
      explain.changeAmount.should.equal('0');
      explain.type.should.equal(TransactionType.AddressInitialization);
      explain.owner?.should.equal(receiver.address);
      explain.proxyType?.should.equal('Any');
      explain.delay?.should.equal('0');
    });

    it('should explain a staking transaction', async () => {
      const json = JSON.parse(jsonTransactions.staking) as Interface.TxData;
      tx.setTxJson(json);
      tx.transactionType(TransactionType.StakingActivate);
      const explain = tx.explainTransaction();
      explain.outputAmount.should.equal('50000000000000');
      explain.outputs[0].amount.should.equal('50000000000000');
      explain.outputs[0].address.should.equal(accounts.account2.address);
      explain.fee.fee.should.equal('0');
      explain.changeAmount.should.equal('0');
      explain.type.should.equal(TransactionType.StakingActivate);
      explain.payee?.should.equal('Staked');
    });

    it('should explain a staking transaction with receiver account', async () => {
      const json = JSON.parse(jsonTransactions.stakingPayee) as Interface.TxData;
      tx.setTxJson(json);
      tx.transactionType(TransactionType.StakingActivate);
      const explain = tx.explainTransaction();
      explain.outputAmount.should.equal('50000000000000');
      explain.outputs[0].amount.should.equal('50000000000000');
      explain.outputs[0].address.should.equal(accounts.account2.address);
      explain.fee.fee.should.equal('0');
      explain.changeAmount.should.equal('0');
      explain.type.should.equal(TransactionType.StakingActivate);
      explain.payee?.should.equal(accounts.account2.address);
    });

    it('should explain a staking unlock transaction', async () => {
      const json = JSON.parse(jsonTransactions.unstaking) as Interface.TxData;
      tx.setTxJson(json);
      tx.transactionType(TransactionType.StakingUnlock);
      const explain = tx.explainTransaction();
      explain.outputAmount.should.equal('50000000000000');
      explain.outputs[0].amount.should.equal('50000000000000');
      explain.outputs[0].address.should.equal(accounts.account1.address);
      explain.fee.fee.should.equal('0');
      explain.changeAmount.should.equal('0');
      explain.type.should.equal(TransactionType.StakingUnlock);
    });
  });

  describe('inputs and outputs', () => {
    it('should generate inputs and output for a batch staking transaction', async () => {
      const builder = new BatchTransactionBuilder(config).material(material);
      builder.from(rawTx.stake.batchAll.signed);
      builder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');

      const tx = await builder.build();

      should(tx.inputs).not.be.null();
      should(tx.inputs.length).eql(2);

      // Staked amount
      should(tx.inputs[0].address).eql(accounts.account1.address);
      should(tx.inputs[0].value).eql('500000000000');
      should(tx.inputs[0].coin).eql('tdot');

      // Add proxy storage fee
      should(tx.inputs[1].address).eql(accounts.account1.address);
      should(tx.inputs[1].value).eql('1002050000000');
      should(tx.inputs[1].coin).eql('tdot');

      should(tx.outputs).not.be.null();
      should(tx.outputs.length).eql(2);

      // Staked amount
      should(tx.outputs[0].address).eql(STAKING_DESTINATION);
      should(tx.outputs[0].value).eql('500000000000');
      should(tx.outputs[0].coin).eql('tdot');

      // Add proxy storage fee
      should(tx.outputs[1].address).eql(accounts.stakingProxy.address);
      should(tx.outputs[1].value).eql('1002050000000');
      should(tx.outputs[1].coin).eql('tdot');
    });

    it('should generate inputs and output for a batch unstaking transaction', async () => {
      const builder = new BatchTransactionBuilder(config).material(material);
      builder.from(rawTx.unstake.batchAll.signed);
      builder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');

      const tx = await builder.build();

      should(tx.inputs).not.be.null();
      should(tx.inputs.length).eql(1);

      // Remove proxy storage fee refund
      should(tx.inputs[0].address).eql(accounts.stakingProxy.address);
      should(tx.inputs[0].value).eql('1002050000000');
      should(tx.inputs[0].coin).eql('tdot');

      should(tx.outputs).not.be.null();
      should(tx.outputs.length).eql(1);

      // Remove proxy storage fee refund
      should(tx.outputs[0].address).eql(accounts.account1.address);
      should(tx.outputs[0].value).eql('1002050000000');
      should(tx.outputs[0].coin).eql('tdot');
    });

    it('should generate inputs and output for a stake more transaction', async () => {
      const builder = new StakingBuilder(config).material(material);
      builder.from(rawTx.stakeMore.signed);
      builder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');

      const tx = await builder.build();

      should(tx.inputs).not.be.null();
      should(tx.inputs.length).eql(1);

      // Amount to add to stake
      should(tx.inputs[0].address).eql(accounts.account1.address);
      should(tx.inputs[0].value).eql('90034235235322');
      should(tx.inputs[0].coin).eql('tdot');

      should(tx.outputs).not.be.null();
      should(tx.outputs.length).eql(1);

      should(tx.outputs[0].address).eql(STAKING_DESTINATION);
      should(tx.outputs[0].value).eql('90034235235322');
      should(tx.outputs[0].coin).eql('tdot');
    });

    it('should generate inputs and output for an unstake transaction', async () => {
      const builder = new UnstakeBuilder(config).material(material);
      builder.from(rawTx.unstake.signed);
      builder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');

      const tx = await builder.build();

      should(tx.inputs).not.be.null();
      should(tx.inputs.length).eql(0);

      should(tx.outputs).not.be.null();
      should(tx.outputs.length).eql(0);
    });

    it('should generate inputs and output for a withdraw staked transaction', async () => {
      const builder = new WithdrawUnstakedBuilder(config).material(material);
      builder.from(rawTx.withdrawUnbonded.signed);
      builder
        .validity({ firstValid: 3933 })
        .referenceBlock('0x149799bc9602cb5cf201f3425fb8d253b2d4e61fc119dcab3249f307f594754d');

      const tx = await builder.build();

      should(tx.inputs).not.be.null();
      should(tx.inputs.length).eql(0);

      should(tx.outputs).not.be.null();
      should(tx.outputs.length).eql(0);
    });
  });
});

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


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