PHP WebShell

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

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

import should from 'should';
import { TransactionType } from '@bitgo/sdk-core';
import {
  ETHTransactionType,
  Fee,
  flushForwarderTokensMethodId,
  flushForwarderTokensMethodIdV4,
  KeyPair,
  Transaction,
} from '../../../src';
import { getBuilder } from '../getBuilder';

describe('Eth Transaction builder flush tokens', function () {
  const defaultKeyPair = new KeyPair({
    prv: 'FAC4D04AA0025ECF200D74BC9B5E4616E4B8338B69B61362AAAD49F76E68EF28',
  });

  interface FlushTokensDetails {
    forwarderAddress?: string;
    tokenAddress?: string;
    contractAddress?: string;
    counter?: number;
    fee?: Fee;
    key?: KeyPair;
    forwarderVersion?: number;
  }

  const buildTransaction = async function (details: FlushTokensDetails): Promise<Transaction> {
    const txBuilder: any = getBuilder('teth');
    txBuilder.type(TransactionType.FlushTokens);

    if (details.forwarderAddress !== undefined) {
      txBuilder.forwarderAddress(details.forwarderAddress);
    }

    if (details.tokenAddress !== undefined) {
      txBuilder.tokenAddress(details.tokenAddress);
    }

    if (details.fee !== undefined) {
      txBuilder.fee(details.fee);
    }

    if (details.contractAddress !== undefined) {
      txBuilder.contract(details.contractAddress);
    }

    if (details.counter !== undefined) {
      txBuilder.counter(details.counter);
    }

    if (details.key !== undefined) {
      txBuilder.sign({ key: details.key.getKeys().prv });
    }

    if (details.forwarderVersion !== undefined) {
      txBuilder.forwarderVersion(details.forwarderVersion);
    }

    return await txBuilder.build();
  };

  describe('should build', () => {
    it('a wallet flush forwarder transaction', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 1,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      });

      tx.type.should.equal(TransactionType.FlushTokens);
      const txJson = tx.toJson();
      txJson.gasLimit.should.equal('1000');
      txJson._type.should.equals(ETHTransactionType.LEGACY);
      txJson.gasPrice!.should.equal('10');
      should.equal(txJson.nonce, 1);
      txJson.data.should.startWith(flushForwarderTokensMethodId);
    });

    it('a wallet flush forwarder transaction with eip1559 fee model', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '30',
          eip1559: {
            maxPriorityFeePerGas: '5',
            maxFeePerGas: '30',
          },
          gasLimit: '1000',
        },
        counter: 1,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      });

      tx.type.should.equal(TransactionType.FlushTokens);
      const txJson = tx.toJson();
      txJson.gasLimit.should.equal('1000');
      txJson._type.should.equals(ETHTransactionType.EIP1559);
      txJson.maxFeePerGas!.should.equal('30');
      txJson.maxPriorityFeePerGas!.should.equal('5');
      should.equal(txJson.nonce, 1);
      txJson.data.should.startWith(flushForwarderTokensMethodId);
    });

    it('a wallet flush forwarder transaction with nonce 0', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      });

      tx.type.should.equal(TransactionType.FlushTokens);
      const txJson = tx.toJson();
      txJson.gasLimit.should.equal('1000');
      txJson._type.should.equals(ETHTransactionType.LEGACY);
      txJson.gasPrice!.should.equal('10');
      should.equal(txJson.nonce, 0);
      txJson.data.should.startWith(flushForwarderTokensMethodId);
    });

    it('a wallet flush forwarder transaction with forwarder Version 4', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        forwarderVersion: 4,
      });

      tx.type.should.equal(TransactionType.FlushTokens);
      const txJson = tx.toJson();
      txJson.gasLimit.should.equal('1000');
      txJson._type.should.equals(ETHTransactionType.LEGACY);
      should.equal(txJson.nonce, 0);
      txJson.data.should.startWith(flushForwarderTokensMethodIdV4);
    });

    it('decode wallet flush forwarder transaction with forwarder Version 4', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        forwarderVersion: 4,
      });
      const txBuiderFromRaw: any = getBuilder('teth');
      txBuiderFromRaw.from(tx.toBroadcastFormat());
      const result = await txBuiderFromRaw.build();
      const txJson = result.toJson();
      txJson.to.should.equal('0x53b8e91bb3b8f618b5f01004ef108f134f219573');
      txJson.data.should.containEql('bcf935d206ca32929e1b887a07ed240f0d8ccd22');
    });

    it('decode wallet flush forwarder transaction with forwarder Version < 4', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
        forwarderVersion: 2,
      });
      const txBuiderFromRaw: any = getBuilder('teth');
      txBuiderFromRaw.from(tx.toBroadcastFormat());
      const result = await txBuiderFromRaw.build();
      const txJson = result.toJson();
      txJson.to.should.equal('0x8f977e912ef500548a0c3be6ddde9899f1199b81');
      txJson.data.should.containEql('bcf935d206ca32929e1b887a07ed240f0d8ccd22');
      txJson.data.should.containEql('53b8e91bb3b8f618b5f01004ef108f134f219573');
    });

    it('an unsigned flush transaction from serialized', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      });
      const serialized = tx.toBroadcastFormat();

      // now rebuild from the signed serialized tx and make sure it stays the same
      const newTxBuilder: any = getBuilder('teth');
      newTxBuilder.from(serialized);
      const newTx = await newTxBuilder.build();
      should.equal(newTx.toBroadcastFormat(), serialized);
      newTx.toJson().data.should.startWith(flushForwarderTokensMethodId);
      should.equal(newTx.toJson().v, '0x77');
    });

    it('a signed flush transaction from serialized', async () => {
      const tx = await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
        key: defaultKeyPair,
      });
      const serialized = tx.toBroadcastFormat();

      // now rebuild from the signed serialized tx and make sure it stays the same
      const newTxBuilder: any = getBuilder('teth');
      newTxBuilder.from(serialized);
      const newTx = await newTxBuilder.build();
      should.equal(newTx.toBroadcastFormat(), serialized);
      should.equal(newTx.id, '0x5bfd4c6b9ae9dfbc9e062247c0debe4e1c6870a76c420ce7f6e335390420dcd6');
      const txJson = newTx.toJson();
      should.exist(txJson.v);
      should.exist(txJson.r);
      should.exist(txJson.s);
      should.exist(txJson.from);
    });
  });

  describe('should fail to build', () => {
    it('a transaction without fee', async () => {
      await buildTransaction({
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      }).should.be.rejectedWith('Invalid transaction: missing fee');
    });

    it('a transaction without contractAddress', async () => {
      await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '10',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
      }).should.be.rejectedWith('Invalid transaction: missing contract address');
    });

    it('a wallet flush forwarder V4 transaction with different contract address', async () => {
      await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '1000',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
        forwarderVersion: 4,
      }).should.be.rejectedWith('Invalid contract address: 0x8f977e912ef500548a0c3be6ddde9899f1199b81');
    });

    it('a transaction without tokenAddress', async () => {
      await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '10',
        },
        counter: 0,
        forwarderAddress: '0x53b8e91bb3b8f618b5f01004ef108f134f219573',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      }).should.be.rejectedWith('Invalid transaction: missing token address');
    });

    it('a transaction without forwarderAddress', async () => {
      await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '10',
        },
        counter: 0,
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      }).should.be.rejectedWith('Invalid transaction: missing forwarder address');
    });

    it('a transaction with invalid counter', async () => {
      await buildTransaction({
        fee: {
          fee: '10',
          gasLimit: '10',
        },
        counter: -1,
        tokenAddress: '0xbcf935d206ca32929e1b887a07ed240f0d8ccd22',
        contractAddress: '0x8f977e912ef500548a0c3be6ddde9899f1199b81',
      }).should.be.rejectedWith('Invalid counter: -1');
    });
  });
});

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


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