PHP WebShell

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

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

import assert from 'assert';
import should from 'should';
import { coins } from '@bitgo/statics';
import { KeyPair, Transaction } from '../../src/lib';
import * as testData from '../resources/sol';
import { PublicKey, Transaction as SolTransaction } from '@solana/web3.js';
import { getBuilderFactory } from './getBuilderFactory';

describe('Sol Transaction', () => {
  const coin = coins.get('tsol');

  describe('toJson should', () => {
    it('throw empty transaction', () => {
      const tx = new Transaction(coin);
      assert.throws(() => tx.toJson(), /Empty transaction/);
      assert.throws(() => tx.toBroadcastFormat(), /Empty transaction/);
    });
    it('throw for toJson of empty tx', () => {
      const tx = new Transaction(coin);
      should(() => tx.toJson()).throwError('Empty transaction');
      tx.solTransaction = new SolTransaction();
      tx.solTransaction.recentBlockhash = testData.blockHashes.validBlockHashes[0];
      should(() => tx.toJson()).throwError('Invalid transaction, transaction type not supported: undefined');
    });

    it('succeed for a unsigned transfer tx', () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.TRANSFER_UNSIGNED_TX_WITH_MEMO_AND_DURABLE_NONCE);
      tx.signature.should.be.empty();
      const txJson = tx.toJson();
      txJson.should.have.properties(['id', 'feePayer', 'nonce', 'numSignatures', 'instructionsData']);
      txJson.id?.should.equal(undefined);
      txJson.feePayer?.should.equal('5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe');
      txJson.nonce.should.equal('GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi');
      txJson.numSignatures.should.equal(0);
      txJson.instructionsData.length.should.equal(3);
      txJson.lamportsPerSignature?.should.be.undefined();
      txJson.instructionsData.should.deepEqual([
        {
          type: 'NonceAdvance',
          params: {
            walletNonceAddress: '8Y7RM6JfcX4ASSNBkrkrmSbRu431YVi9Y3oLFnzC2dCh',
            authWalletAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: 'CP5Dpaa42RtJmMuKqCQsLwma5Yh3knuvKsYDFX85F41S',
            amount: '300000',
          },
        },
        {
          type: 'Memo',
          params: {
            memo: 'test memo',
          },
        },
      ]);
    });

    it('succeed for a multi transfer tx', () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.MULTI_TRANSFER_SIGNED);
      const txJson = tx.toJson();
      txJson.should.have.properties(['id', 'feePayer', 'nonce', 'numSignatures', 'instructionsData']);
      txJson.id?.should.equal(
        'TPVcc18CYxPnM3eRgQhdb6V6ZLa34Dv3dU7MtvKPuy5ZPKLM1uZPFFEmF2m184PTWKRZ1Uq6NKFZWwr2krKk63f'
      );
      tx.signature.should.deepEqual([
        'TPVcc18CYxPnM3eRgQhdb6V6ZLa34Dv3dU7MtvKPuy5ZPKLM1uZPFFEmF2m184PTWKRZ1Uq6NKFZWwr2krKk63f',
      ]);
      txJson.feePayer?.should.equal('5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe');
      txJson.nonce.should.equal('GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi');
      txJson.numSignatures.should.equal(1);
      txJson.lamportsPerSignature?.should.be.undefined();
      txJson.instructionsData.length.should.equal(8);
      txJson.instructionsData.should.deepEqual([
        {
          type: 'NonceAdvance',
          params: {
            walletNonceAddress: '8Y7RM6JfcX4ASSNBkrkrmSbRu431YVi9Y3oLFnzC2dCh',
            authWalletAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: 'CP5Dpaa42RtJmMuKqCQsLwma5Yh3knuvKsYDFX85F41S',
            amount: '300000',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: '6B55XMiaS6tUZw5Tt3G1RaXAqdrvN38yXVDJmWvKLkiM',
            amount: '300000',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: 'C1UjpxcXNBpp1UyvYsuNBNZ5Da1G1i49g3yTvC23Ny7e',
            amount: '300000',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: 'CpUYXh9xXoWfkBVaBQRZ8nAgDbT16GZeQdqveeBS1hmk',
            amount: '300000',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: '64s6NjmEokdhicHEd432X5Ut2EDfDmVqdvGh4rASn1gd',
            amount: '300000',
          },
        },
        {
          type: 'Transfer',
          params: {
            fromAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            toAddress: '6nXxL2jMSdkgfHm13Twvn1gzRAPdrWnWLfu89PJL3Aqe',
            amount: '300000',
          },
        },
        {
          type: 'Memo',
          params: {
            memo: 'test memo',
          },
        },
      ]);
    });
  });

  describe('sign should', () => {
    it('fail if the tx doesnt have nonce', async () => {
      const tx = new Transaction(coin);
      tx.solTransaction = new SolTransaction();
      tx.solTransaction.feePayer = new PublicKey(testData.authAccount.pub);
      const kp = new KeyPair({ prv: testData.prvKeys.prvKey1.base58 });
      await tx.sign(kp).should.be.rejectedWith('Nonce is required before signing');
    });

    it('fail if the tx doesnt have feePayer', async () => {
      const tx = new Transaction(coin);
      const kp = new KeyPair({ prv: testData.prvKeys.prvKey1.base58 });
      tx.solTransaction = new SolTransaction();
      tx.solTransaction.recentBlockhash = testData.blockHashes.validBlockHashes[0];
      await tx.sign(kp).should.be.rejectedWith('feePayer is required before signing');
    });

    it('fail if the KeyPair is not the right one', async () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_UNSIGNED);
      const keypair = new KeyPair({ prv: testData.prvKeys.prvKey1.base58 });
      await tx.sign(keypair).should.be.rejectedWith('unknown signer: CP5Dpaa42RtJmMuKqCQsLwma5Yh3knuvKsYDFX85F41S');
    });

    it('fail if the KeyPair doesnt have a prv key', async () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_UNSIGNED);
      const keypair = new KeyPair({ pub: testData.pubKeys.validPubKeys[0] });
      await tx.sign(keypair).should.be.rejectedWith('Missing private key');
    });

    it('succeed to sign with 1 KeyPair', async () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_UNSIGNED);
      const keypair = new KeyPair({ prv: testData.accountWithSeed.privateKey.base58 });
      await tx.sign(keypair).should.be.fulfilled();
      should.equal(tx.toBroadcastFormat(), testData.RAW_TX_SIGNED);
    });

    it('succeed when try to sign with the same keyPair multiple times ', async () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_UNSIGNED);
      const keypair = new KeyPair({ prv: testData.accountWithSeed.privateKey.base58 });
      await tx.sign([keypair, keypair, keypair, keypair]).should.be.fulfilled();
      should.equal(tx.toBroadcastFormat(), testData.RAW_TX_SIGNED);
    });

    it('succeed when try to sign with a keyPair that already signed', async () => {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_SIGNED);
      const keypair = new KeyPair({ prv: testData.accountWithSeed.privateKey.base58 });
      await tx.sign(keypair).should.be.fulfilled();
      should.equal(tx.toBroadcastFormat(), testData.RAW_TX_SIGNED);
    });
  });

  describe('transaction parsing', function () {
    it('fromRawTransaction and toBroadcastFormat', async function () {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_UNSIGNED);
      should.equal(tx.toBroadcastFormat(), testData.RAW_TX_UNSIGNED);
    });

    it('fromRawTransaction, sign and toBroadcastFormat ', async function () {
      const tx = new Transaction(coin);
      tx.fromRawTransaction(testData.RAW_TX_UNSIGNED);
      const keypair = new KeyPair({ prv: testData.accountWithSeed.privateKey.base58 });
      await tx.sign(keypair);
      should.equal(tx.toBroadcastFormat(), testData.RAW_TX_SIGNED);
    });
  });

  describe('explain transaction', function () {
    const factory = getBuilderFactory('tsol');
    const blockHash = testData.blockHashes.validBlockHashes[0];
    const sender = testData.authAccount.pub;
    const address = testData.addresses.validAddresses[0];
    const amount = '10000';
    const wallet = new KeyPair(testData.authAccount).getKeys();
    const stakeAccount = new KeyPair(testData.stakeAccount).getKeys();
    const validator = testData.validator;

    it('should explain single transfer transaction', async function () {
      const tx = await factory
        .getTransferBuilder()
        .nonce(blockHash)
        .sender(sender)
        .send({ address, amount })
        .fee({ amount: 5000 })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'Send',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H',
            amount: '10000',
          },
        ],
        fee: {
          fee: '5000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should explain single transfer with durable nonce transaction', async function () {
      const tx = await factory
        .getTransferBuilder()
        .nonce(blockHash, { walletNonceAddress: testData.nonceAccount.pub, authWalletAddress: sender })
        .sender(sender)
        .send({ address, amount })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'Send',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H',
            amount: '10000',
          },
        ],
        fee: {
          fee: 'UNAVAILABLE',
          feeRate: undefined,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: {
          authWalletAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
          walletNonceAddress: '8Y7RM6JfcX4ASSNBkrkrmSbRu431YVi9Y3oLFnzC2dCh',
        },
      });
    });

    it('should explain multi transfer with durable nonce and memo transaction', async function () {
      const tx = await factory
        .getTransferBuilder()
        .nonce(blockHash, { walletNonceAddress: testData.nonceAccount.pub, authWalletAddress: sender })
        .sender(sender)
        .memo('memo text')
        .send({ address, amount })
        .send({ address: testData.addresses.validAddresses[1], amount })
        .send({ address: testData.addresses.validAddresses[2], amount })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'Send',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '30000',
        outputs: [
          {
            address: 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H',
            amount: '10000',
          },
          {
            address: 'Azz9EmNuhtjoYrhWvidWx1Hfd14SNBsYyzXhA9Tnoca8',
            amount: '10000',
          },
          {
            address: '2n2xqWM9Z18LqxfJzkNrMMFWiDUFYA2k6WSgSnf6EnJs',
            amount: '10000',
          },
        ],
        fee: {
          fee: 'UNAVAILABLE',
          feeRate: undefined,
        },
        memo: 'memo text',
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: {
          authWalletAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
          walletNonceAddress: '8Y7RM6JfcX4ASSNBkrkrmSbRu431YVi9Y3oLFnzC2dCh',
        },
      });
    });

    it('should explain signed transfer transaction', async function () {
      const tx = await factory
        .getTransferBuilder()
        .fee({ amount: 5000 })
        .nonce(blockHash)
        .sender(sender)
        .send({ address, amount })
        .build();
      await (tx as Transaction).sign(new KeyPair({ prv: testData.authAccount.prv }));

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: tx.id,
        type: 'Send',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H',
            amount: '10000',
          },
        ],
        fee: {
          fee: '5000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should explain wallet init transaction', async function () {
      const tx = await factory
        .getWalletInitializationBuilder()
        .fee({ amount: 5000 })
        .sender(sender)
        .nonce(blockHash)
        .address(testData.addresses.validAddresses[1])
        .amount(amount)
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'WalletInitialization',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: 'Azz9EmNuhtjoYrhWvidWx1Hfd14SNBsYyzXhA9Tnoca8',
            amount: '10000',
          },
        ],
        fee: {
          fee: '10000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should explain wallet init with durable nonce and memo transaction', async function () {
      const tx = await factory
        .getWalletInitializationBuilder()
        .sender(sender)
        .nonce(blockHash, { walletNonceAddress: testData.nonceAccount.pub, authWalletAddress: sender })
        .memo('memo text')
        .address(testData.addresses.validAddresses[1])
        .amount(amount)
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'WalletInitialization',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: 'Azz9EmNuhtjoYrhWvidWx1Hfd14SNBsYyzXhA9Tnoca8',
            amount: '10000',
          },
        ],
        fee: {
          fee: 'UNAVAILABLE',
          feeRate: undefined,
        },
        memo: 'memo text',
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: {
          authWalletAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
          walletNonceAddress: '8Y7RM6JfcX4ASSNBkrkrmSbRu431YVi9Y3oLFnzC2dCh',
        },
      });
    });

    it('should explain signed wallet init transaction', async function () {
      const tx = await factory
        .getWalletInitializationBuilder()
        .fee({ amount: 5000 })
        .sender(sender)
        .nonce(blockHash)
        .address(testData.addresses.validAddresses[1])
        .amount(amount)
        .build();
      await (tx as Transaction).sign(new KeyPair({ prv: testData.authAccount.prv }));

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: tx.id,
        type: 'WalletInitialization',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: 'Azz9EmNuhtjoYrhWvidWx1Hfd14SNBsYyzXhA9Tnoca8',
            amount: '10000',
          },
        ],
        fee: {
          fee: '10000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should explain create ATA transaction', async function () {
      const tx = await factory
        .getAtaInitializationBuilder()
        .fee({ amount: 5000 })
        .sender(sender)
        .nonce(blockHash)
        .mint('tsol:usdc')
        .rentExemptAmount(amount)
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'AssociatedTokenAccountInitialization',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '0',
        outputs: [],
        fee: {
          fee: '15000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should activate builder ', async function () {
      const tx = await factory
        .getStakingActivateBuilder()
        .stakingAddress(stakeAccount.pub)
        .sender(wallet.pub)
        .nonce(blockHash)
        .amount(amount)
        .validator(validator.pub)
        .fee({ amount: 5000 })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'StakingActivate',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: '7dRuGFbU2y2kijP6o1LYNzVyz4yf13MooqoionCzv5Za',
            amount: '10000',
          },
        ],
        fee: {
          fee: '10000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should deactivate builder ', async function () {
      const recentBlockHash = 'GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi';
      const tx = await factory
        .getStakingDeactivateBuilder()
        .stakingAddress(stakeAccount.pub)
        .sender(wallet.pub)
        .stakingAddress(stakeAccount.pub)
        .nonce(recentBlockHash)
        .fee({ amount: 5000 })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'StakingDeactivate',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '0',
        outputs: [],
        fee: {
          fee: '5000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: 'GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi',
        durableNonce: undefined,
      });
    });

    it('should explain withdraw transaction ', async function () {
      const recentBlockHash = 'GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi';
      const tx = await factory
        .getStakingWithdrawBuilder()
        .stakingAddress(stakeAccount.pub)
        .sender(wallet.pub)
        .amount(amount)
        .nonce(recentBlockHash)
        .fee({ amount: 5000 })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'StakingWithdraw',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            amount: '10000',
          },
        ],
        fee: {
          fee: '5000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: 'GHtXQBsoZHVnNFa9YevAzFr17DJjgHXk3ycTKD5xD3Zi',
        durableNonce: undefined,
      });
    });

    it('should explain withdraw transaction with memo and durable nonce ', async function () {
      const tx = await factory
        .getStakingWithdrawBuilder()
        .stakingAddress(stakeAccount.pub)
        .sender(wallet.pub)
        .amount(amount)
        .nonce(blockHash, { walletNonceAddress: testData.nonceAccount.pub, authWalletAddress: sender })
        .memo('memo text')
        .fee({ amount: 5000 })
        .build();
      tx.signablePayload;

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'StakingWithdraw',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '10000',
        outputs: [
          {
            address: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
            amount: '10000',
          },
        ],
        fee: {
          fee: '5000',
          feeRate: 5000,
        },
        memo: 'memo text',
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: {
          walletNonceAddress: testData.nonceAccount.pub,
          authWalletAddress: sender,
        },
      });
    });

    it('should explain single token transfer transaction', async function () {
      const tx = await factory
        .getTokenTransferBuilder()
        .nonce(blockHash)
        .sender(sender)
        .send({ address, amount, tokenName: 'tsol:usdc' })
        .fee({ amount: 5000 })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'Send',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '0',
        outputs: [
          {
            address: 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H',
            amount: '10000',
            tokenName: 'tsol:usdc',
          },
        ],
        fee: {
          fee: '5000',
          feeRate: 5000,
        },
        memo: undefined,
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: undefined,
      });
    });

    it('should explain multi token transfer with durable nonce and memo transaction', async function () {
      const tx = await factory
        .getTokenTransferBuilder()
        .nonce(blockHash, { walletNonceAddress: testData.nonceAccount.pub, authWalletAddress: sender })
        .sender(sender)
        .memo('memo text')
        .send({ address, amount, tokenName: 'tsol:usdc' })
        .send({ address: testData.addresses.validAddresses[1], amount, tokenName: 'tsol:usdc' })
        .send({ address: testData.addresses.validAddresses[2], amount, tokenName: 'tsol:usdc' })
        .build();

      const explainedTransaction = tx.explainTransaction();
      explainedTransaction.should.deepEqual({
        displayOrder: [
          'id',
          'type',
          'blockhash',
          'durableNonce',
          'outputAmount',
          'changeAmount',
          'outputs',
          'changeOutputs',
          'fee',
          'memo',
        ],
        id: 'UNAVAILABLE',
        type: 'Send',
        changeOutputs: [],
        changeAmount: '0',
        outputAmount: '0',
        outputs: [
          {
            address: 'DesU7XscZjng8yj5VX6AZsk3hWSW4sQ3rTG2LuyQ2P4H',
            amount: '10000',
            tokenName: 'tsol:usdc',
          },
          {
            address: 'Azz9EmNuhtjoYrhWvidWx1Hfd14SNBsYyzXhA9Tnoca8',
            amount: '10000',
            tokenName: 'tsol:usdc',
          },
          {
            address: '2n2xqWM9Z18LqxfJzkNrMMFWiDUFYA2k6WSgSnf6EnJs',
            amount: '10000',
            tokenName: 'tsol:usdc',
          },
        ],
        fee: {
          fee: 'UNAVAILABLE',
          feeRate: undefined,
        },
        memo: 'memo text',
        blockhash: '5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
        durableNonce: {
          authWalletAddress: '5hr5fisPi6DXNuuRpm5XUbzpiEnmdyxXuBDTwzwZj5Pe',
          walletNonceAddress: '8Y7RM6JfcX4ASSNBkrkrmSbRu431YVi9Y3oLFnzC2dCh',
        },
      });
    });
  });
});

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


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