From 3cdf63ad70b59f0af6a5effc9503a47846a53ae6 Mon Sep 17 00:00:00 2001 From: nagdahimanshu Date: Tue, 6 Feb 2024 21:42:02 +0100 Subject: [PATCH] :white_check_mark: Add unit tests --- services/export/shared/regex.js | 2 +- services/export/shared/transactionsExport.js | 7 + services/export/tests/constants/blocks.js | 35 + services/export/tests/constants/events.js | 167 ++++ .../export/tests/constants/transaction.js | 114 +++ .../tests/unit/shared/helpers/account.test.js | 204 ++++- .../tests/unit/shared/helpers/chain.test.js | 2 +- .../tests/unit/shared/helpers/file.test.js | 113 ++- .../tests/unit/shared/helpers/time.test.js | 36 +- .../unit/shared/helpers/transaction.test.js | 4 +- .../unit/shared/transactionsExport.test.js | 741 ++++++++++-------- 11 files changed, 1017 insertions(+), 408 deletions(-) create mode 100644 services/export/tests/constants/events.js diff --git a/services/export/shared/regex.js b/services/export/shared/regex.js index 470896586b..9fbfa8002a 100644 --- a/services/export/shared/regex.js +++ b/services/export/shared/regex.js @@ -22,7 +22,7 @@ const PARTIAL_FILENAME = const STANDARDIZED_INTERVAL = /^\b((\d{4})-((1[012])|(0?[1-9]))-(([012][1-9])|([123]0)|31)):((\d{4})-((1[012])|(0?[1-9]))-(([012][1-9])|([123]0)|31))\b$/g; const EXCEL_FILE_URL = - /^\/api\/v3\/export\/download\?filename=transactions_(lsk[a-hjkm-z2-9]{38})_((\d{4})-((1[012])|(0?[1-9]))-(([012][1-9])|([123]0)|31))_((\d{4})-((1[012])|(0?[1-9]))-(([012][1-9])|([123]0)|31))\.xlsx$/g; + /^\/api\/v3\/export\/download\?filename=transactions_([a-fA-F0-9]{8})_(lsk[a-hjkm-z2-9]{38})_((\d{4})-((1[012])|(0?[1-9]))-(([012][1-9])|([123]0)|31))_((\d{4})-((1[012])|(0?[1-9]))-(([012][1-9])|([123]0)|31))\.xlsx$/g; const MAINCHAIN_ID = /^[a-fA-F0-9]{2}000000$/; module.exports = { diff --git a/services/export/shared/transactionsExport.js b/services/export/shared/transactionsExport.js index 93b33377e3..2199f8c115 100644 --- a/services/export/shared/transactionsExport.js +++ b/services/export/shared/transactionsExport.js @@ -980,4 +980,11 @@ module.exports = { // For functional tests formatTransaction, formatBlocks, + getChainInfo, + getBlockRewardEntries, + getGeneratorFeeEntries, + getSharedRewardsAssignedEntries, + getMessageFeeEntries, + getOutgoingTransferCCEntries, + getIncomingTransferCCEntries, }; diff --git a/services/export/tests/constants/blocks.js b/services/export/tests/constants/blocks.js index 3a83022613..d32aed2b41 100644 --- a/services/export/tests/constants/blocks.js +++ b/services/export/tests/constants/blocks.js @@ -78,6 +78,41 @@ const blocks = [ isFinal: false, reward: 0, }, + + { + id: 'bc62dabae94b2d146a9fb72424b87d65cfdc4b41d57d7e95343a8bd246b74b75', + version: 2, + timestamp: 1704198870, + height: 21016494, + previousBlockID: '40cf694c59aa0f4ccddaf1b37e77c752c5b2ae17253c76dbe26a8463be204fdb', + generator: { + address: 'lskkg45aupy3mnzeko7thpgzwaqh9cjcrjfo46kjt', + name: 'different_dish', + publicKey: 'ae79e3d4fcfc8b9d7acbf2a72f2281cb85a98cd9a5b18b2164b06113032bea78', + }, + transactionRoot: '5b24f16b9313b7954c086743ab784af77ecab4854cff5538c14633b50bb728fa', + assetRoot: 'f74d106522e5f9350edc170eb8603168438c85030d6294a37239961ab10bfd3a', + stateRoot: 'e0587de5aabe73bf478a9f94aeae9ee86e771d1cc01d9ee3b78d8d45aa278abd', + eventRoot: '907db89b436269e870cc234844fd4d26e484380d33b724d078cf65deebbe0e44', + maxHeightPrevoted: 21016419, + maxHeightGenerated: 21016363, + validatorsHash: 'f111c95be02cd8924791a24c97bc1a014a8aad7906b85f1f4ecc40e195234211', + aggregateCommit: { + height: 21016347, + aggregationBits: '', + }, + certificateSignature: '', + numberOfTransactions: 1, + numberOfAssets: 1, + numberOfEvents: 10, + totalForged: '22268530', + totalBurnt: '194000', + networkFee: '9806000', + signature: + 'e25aefd645ae92251e029c0679486464ed10795ee27955243e99436f977cbfec185c7cd6a66d57516a65f59b83990c9998519212e9002a43b8371245361ba606', + reward: '12268530', + isFinal: true, + }, ]; module.exports = { diff --git a/services/export/tests/constants/events.js b/services/export/tests/constants/events.js new file mode 100644 index 0000000000..e86f0473d3 --- /dev/null +++ b/services/export/tests/constants/events.js @@ -0,0 +1,167 @@ +/* + * LiskHQ/lisk-service + * Copyright © 2024 Lisk Foundation + * + * See the LICENSE file at the top-level directory of this distribution + * for licensing information. + * + * Unless otherwise agreed in a custom licensing agreement with the Lisk Foundation, + * no part of this software, including this file, may be copied, modified, + * propagated, or distributed except according to the terms contained in the + * LICENSE file. + * + * Removal or modification of this copyright notice is prohibited. + * + */ +const tokenMintedEvent = { + id: '000f293a862a5b5c55f44cba8fb656cdab94ce4ebd99cc9f97329b87a70248f3', + module: 'token', + name: 'lock', + data: { + address: 'lskbrukhb5ctdodhy8z6any4b6u2qrkugz43w78pr', + module: 'fee', + tokenID: '0100000000000000', + amount: '161000', + result: 0, + }, + topics: [ + '041c425c907ba819e64da0166de38fe50ae9de29d9a3fd2bbeda2e89c045917fe3', + 'lskbrukhb5ctdodhy8z6any4b6u2qrkugz43w78pr', + ], +}; + +const tokenLockedEvent = { + id: 'e2e8622d572985863166015c62b90ad0c8339f6eb9331eff7eb8011d89882358', + module: 'token', + name: 'mint', + data: { + address: 'lskywqe2cuw5j9burca4sm6rpfxnxyzksv5r99b9g', + tokenID: '0100000000000000', + amount: '131000', + result: 0, + }, + topics: ['03', 'lskywqe2cuw5j9burca4sm6rpfxnxyzksv5r99b9g'], +}; + +const genFeeProcessed = { + id: 'ab21335d06196f58608c60c77fa2cfc285697a5471d95fa295521d6798d32e5d', + module: 'fee', + name: 'generatorFeeProcessed', + data: { + senderAddress: 'lskmv6entvj8cnrhfdoa38ojx34pv4rd9q44788r7', + generatorAddress: 'lskme8ohf9geuno8nwpvdqm8wr8bvz5nzguftwpxp', + burntAmount: '179000', + generatorAmount: '21000', + }, + topics: [ + '04d41e8fbb909fdf44ffccef6f5b0fb5edf853f0dcf699243a0a92403d2a4f1d1d', + 'lskmv6entvj8cnrhfdoa38ojx34pv4rd9q44788r7', + 'lskme8ohf9geuno8nwpvdqm8wr8bvz5nzguftwpxp', + ], +}; + +const rewardsAssigned = { + id: '5630ae1886ab96412db5924193ee1782ac4acc72c6196e8eadb0cf8adbef3de2', + module: 'pos', + name: 'rewardsAssigned', + data: { + stakerAddress: 'lskmg3sdmjp4smz6x9k2cuyuwags5ehgtexe4w2ds', + validatorAddress: 'lsk26s9p9rb74ygzxayuf9cx6x7x5wuvp2v9yrns7', + tokenID: '0100000000000000', + amount: '87694485125', + }, + topics: [ + '04732923c6e8780251c1dcd179e3e657827ae9318a6df920de595d743f1ed70a40', + 'lskmg3sdmjp4smz6x9k2cuyuwags5ehgtexe4w2ds', + ], +}; + +const relayerFeeProcessed = { + id: '40f44afac6097dcec6dfd945000990f0ea95e7a1ad9e86562cb02ee36ee39e4c', + module: 'interoperability', + name: 'relayerFeeProcessed', + data: { + ccmID: 'e6a22f3c4489ceba8e20eeea0ce617d9c385e92aeb9a710a53eb941d34b5f92e', + relayerAddress: 'lskmg3sdmjp4smz6x9k2cuyuwags5ehgtexe4w2ds', + burntAmount: '10000000', + relayerAmount: '0', + }, + topics: ['lskmg3sdmjp4smz6x9k2cuyuwags5ehgtexe4w2ds'], +}; + +const ccmSendSuccess = { + id: 'df34de3aa6461285698e023135edf6708e963510048a9be5b5a7acfe1ecd3ac1', + module: 'interoperability', + name: 'ccmSendSuccess', + data: { + ccm: { + module: 'token', + crossChainCommand: 'transferCrossChain', + nonce: '57', + fee: '109000', + sendingChainID: '04000000', + receivingChainID: '04000002', + params: + '0a0801000000000000001080c2d72f1a145a88fb2d14453327d896adc860e711d26123bd9022145a88fb2d14453327d896adc860e711d26123bd902a00', + status: 0, + }, + }, + topics: [ + '0434548b99aa37a5a450712c7e3f1e13b62be872d65dd7a8c1d54859408ca4914b', + '01000000', + '01000002', + '5ec6bd1dbbcecaef8edad082cfd333c7cf1fdbfeb248c8a80a236179484d06c8', + ], +}; + +const transferCrossChain = { + id: 'f01ba39c143282f7a21e2680b50f7b9b8450afcabc24c35dd72793e389a1bcab', + module: 'token', + name: 'transferCrossChain', + data: { + senderAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + recipientAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + tokenID: '0400000000000000', + amount: '100000000', + receivingChainID: '04000002', + result: 0, + }, + topics: [ + '0434548b99aa37a5a450712c7e3f1e13b62be872d65dd7a8c1d54859408ca4914b', + 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + '01000002', + ], +}; + +const ccmTransfer = { + id: 'f01ba39c143282f7a21e2680b50f7b9b8450afcabc24c35dd72793e389a1bcab', + module: 'token', + name: 'transferCrossChain', + data: { + senderAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + recipientAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + tokenID: '0400000000000000', + amount: '100000000', + receivingChainID: '04000002', + result: 0, + }, + topics: [ + 'd16d1cb5fa32df64988b4ab5de66b7d43c8fbfdaf043aca84d649f914d66189f', + 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + ], +}; + +module.exports = { + events: { + tokenMintedEvent, + tokenLockedEvent, + genFeeProcessed, + rewardsAssigned, + relayerFeeProcessed, + ccmSendSuccess, + transferCrossChain, + ccmTransfer, + }, +}; diff --git a/services/export/tests/constants/transaction.js b/services/export/tests/constants/transaction.js index e61eb4866d..2bda9270b3 100644 --- a/services/export/tests/constants/transaction.js +++ b/services/export/tests/constants/transaction.js @@ -177,6 +177,117 @@ const tokenTransferCrossChainTransaction = { index: 1, }; +const posClaimedRewards = { + id: '732923c6e8780251c1dcd179e3e657827ae9318a6df920de595d743f1ed70a40', + moduleCommand: 'pos:claimRewards', + nonce: '92', + fee: '127000', + minFee: '127000', + size: 127, + block: { + id: 'd6be2fd9ebd06406122ed971b7638621b8f5104f84b46e21d4067fd28b3db72e', + height: 21304948, + timestamp: 1707134570, + isFinal: true, + }, + sender: { + address: 'lskmg3sdmjp4smz6x9k2cuyuwags5ehgtexe4w2ds', + publicKey: 'f0fda0461215e4e63a68d12c79d293833c32519cfe3a5e01ca08b0a0a7493de5', + name: null, + }, + params: {}, + signatures: [ + 'd219f9362bd2a6fcd8357bcfdc26b66efade5526407d884e4f34750934965b1f3367f7f71e9ddfd29160f6b101a0136ee456a1b7721519d85fff6d6ca65be401', + ], + executionStatus: 'successful', + index: 0, +}; + +const transferCrossChain = { + id: '34548b99aa37a5a450712c7e3f1e13b62be872d65dd7a8c1d54859408ca4914b', + moduleCommand: 'token:transferCrossChain', + nonce: '41', + fee: '10000000', + minFee: '194000', + size: 195, + block: { + id: 'bc62dabae94b2d146a9fb72424b87d65cfdc4b41d57d7e95343a8bd246b74b75', + height: 21016494, + timestamp: 1704198870, + isFinal: true, + }, + sender: { + address: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + publicKey: '344c75738c096e4bd94459fe81eba45503382181d003a9d2c8be75a2f38b49fa', + name: null, + }, + params: { + tokenID: '0400000000000000', + amount: '100000000', + receivingChainID: '04000002', + recipientAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + data: '', + messageFee: '109000', + messageFeeTokenID: '0400000000000000', + }, + signatures: [ + 'cbe755352a175b11a3dc4ae4b5e890ebc4ce1d5cc11c6dbdf5cf21b19f7605e7845b4650779191fdbfc1a1afe90edc1a049717b60858f140f4ae0ad67e93d505', + ], + executionStatus: 'successful', + index: 0, + meta: { + recipient: { + address: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + publicKey: '344c75738c096e4bd94459fe81eba45503382181d003a9d2c8be75a2f38b49fa', + name: null, + }, + }, +}; + +const submitMainchainCrossChainUpdate = { + id: 'd16d1cb5fa32df64988b4ab5de66b7d43c8fbfdaf043aca84d649f914d66189f', + moduleCommand: 'interoperability: submitMainchainCrossChainUpdate', + nonce: '140', + fee: '3000000', + minFee: '422000', + size: 423, + block: { + id: '5333974cf1763909f6e63e4a419d942ae4a6a0a2f3477e620f214cf23a4c7342', + height: 21102804, + timestamp: 1705079500, + isFinal: true, + }, + sender: { + address: 'lskcd7tbbhkyebmg2fhdd4w4omvnfhzp5rb7wmz4d', + publicKey: 'b5e96c1a5ab6f9d96eb08360cbfe4f1d8826591c515d307b9b9eeb1567a19013', + name: null, + }, + params: { + sendingChainID: '04000000', + certificate: + '0a20e38e39a33032916b31c6f092047d6aa4919d88760b9185fe631c19d1669a45fc10f60418f4ac84ad0622204dd143faa3c027e456369f75c89bd32befb9229dfcc3cd0b83ecbbca1e0656a42a2076965cc0331adc28fd8d16e63a64d6520397ee3fb3397da59afe60a506bcd909320dffffffffffffffffffffffff013a60b42c2b251e7621e8fd4915167a8360967860898484f29d0faf1e5536ba74bae59da15de420e209182843f884e6aea1b7078095fbeffdbac4169ac3689d06a49e49abd9a4aa9ee78708b7978e2de477993589ed0d2114d3fca5267da867510502', + activeValidatorsUpdate: { + blsKeysUpdate: [], + bftWeightsUpdate: ['0'], + bftWeightsUpdateBitmap: '00000000000000000020000000', + }, + certificateThreshold: '65', + inboxUpdate: { + crossChainMessages: [], + messageWitnessHashes: [], + outboxRootWitness: { + bitmap: '', + siblingHashes: [], + }, + }, + }, + signatures: [ + 'ded5534277972e71ca062b3ac58ce1e6e71fe5f9b5a91c091e5e8ddc879726263c2c6cd23bc1ca1e18f5cdc36767ca243773180ee05caa7bbe724324c20a300d', + ], + executionStatus: 'failed', + index: 0, +}; + module.exports = { transactions: { reclaim: reclaimTransaction, @@ -184,5 +295,8 @@ module.exports = { tokenTransferSelf: tokenTransferTransactionSelf, tokenTransferCrossChain: tokenTransferCrossChainTransaction, stake: stakeTransaction, + claimedRewards: posClaimedRewards, + transferCrossChain, + submitMainchainCrossChainUpdate, }, }; diff --git a/services/export/tests/unit/shared/helpers/account.test.js b/services/export/tests/unit/shared/helpers/account.test.js index c9c75a6b1a..33ebcafb26 100644 --- a/services/export/tests/unit/shared/helpers/account.test.js +++ b/services/export/tests/unit/shared/helpers/account.test.js @@ -15,25 +15,26 @@ */ const { resolve } = require('path'); -const { - validateLisk32Address, - validatePublicKey, - getLisk32AddressFromPublicKey, - getAddressFromParams, -} = require('../../../../shared/helpers/account'); - const { valid, invalid } = require('../../../constants/account'); +const { transactions } = require('../../../constants/transaction'); const mockedRequestFilePath = resolve(`${__dirname}/../../../../shared/helpers/request`); +const mockedRequestAllFilePath = resolve(`${__dirname}/../../../../shared/helpers/requestAll`); + +beforeEach(() => jest.resetModules()); describe('Account utils', () => { describe('Validate address', () => { it('returns true for valid Lisk32 address', async () => { + const { validateLisk32Address } = require('../../../../shared/helpers/account'); + const isValid = validateLisk32Address(valid.address); expect(isValid).toBe(true); }); it('returns false for invalid Lisk32 address', async () => { + const { validateLisk32Address } = require('../../../../shared/helpers/account'); + const isInvalid = validateLisk32Address(invalid.address); expect(isInvalid).toBe(false); }); @@ -41,11 +42,15 @@ describe('Account utils', () => { describe('Validate publicKey', () => { it('returns true for valid publicKey', async () => { + const { validatePublicKey } = require('../../../../shared/helpers/account'); + const isValid = validatePublicKey(valid.publicKey); expect(isValid).toBe(true); }); it('returns false for invalid publicKey', async () => { + const { validatePublicKey } = require('../../../../shared/helpers/account'); + const isInvalid = validatePublicKey(invalid.publicKey); expect(isInvalid).toBe(false); }); @@ -53,6 +58,8 @@ describe('Account utils', () => { describe('Extract address from a valid publicKey', () => { it('returns correct Lisk32 address from a valid publicKey', async () => { + const { getLisk32AddressFromPublicKey } = require('../../../../shared/helpers/account'); + const address = getLisk32AddressFromPublicKey(valid.publicKey); expect(address).toBe(valid.address); }); @@ -63,11 +70,15 @@ describe('Account utils', () => { const publicKey = '86cbecb2a176934e454f63e7ffa05783be6960d90002c5558dfd31397cd8f020'; it('should return address from address in params', async () => { + const { getAddressFromParams } = require('../../../../shared/helpers/account'); + const result = getAddressFromParams({ address }); expect(result).toBe(address); }); it('should return address from publicKey in params', async () => { + const { getAddressFromParams } = require('../../../../shared/helpers/account'); + const result = getAddressFromParams({ publicKey }); expect(result).toBe(address); }); @@ -75,17 +86,12 @@ describe('Account utils', () => { describe('Test checkIfAccountExists method', () => { it('should return true when account exists', async () => { - jest.mock(mockedRequestFilePath, () => { - const actual = jest.requireActual(mockedRequestFilePath); - return { - ...actual, - requestIndexer() { - return { - data: { isExists: true }, - meta: {}, - }; - }, - }; + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestIndexer } = require(mockedRequestFilePath); + requestIndexer.mockResolvedValueOnce({ + data: { isExists: true }, + meta: {}, }); const { checkIfAccountExists } = require('../../../../shared/helpers/account'); @@ -97,44 +103,158 @@ describe('Account utils', () => { }); }); - describe('Test getOpeningBalance method', () => { - it('should return opening balance when called with valid address', async () => { - const mockUserSubstore = { - address: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - availableBalance: '100000000000000', - lockedBalances: [], - tokenID: '0400000000000000', - }; + describe('Test checkIfAccountHasTransactions method', () => { + it('should return true when account has transactions', async () => { + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestIndexer } = require(mockedRequestFilePath); + requestIndexer.mockResolvedValueOnce({ + data: [transactions.tokenTransfer], + meta: {}, + }); + + const { checkIfAccountHasTransactions } = require('../../../../shared/helpers/account'); + + const isAccountHasTransactions = await checkIfAccountHasTransactions( + 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + ); + expect(isAccountHasTransactions).toEqual(true); + }); + + it('should return false when account has no transactions', async () => { + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestIndexer } = require(mockedRequestFilePath); + requestIndexer.mockResolvedValueOnce({ + data: [], + meta: {}, + }); + + const { checkIfAccountHasTransactions } = require('../../../../shared/helpers/account'); + + const isAccountHasTransactions = await checkIfAccountHasTransactions( + 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + ); + expect(isAccountHasTransactions).toEqual(false); + }); + }); + + describe('Test checkIfAccountIsValidator method', () => { + it('should return true when account is a validator', async () => { + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestIndexer } = require(mockedRequestFilePath); + requestIndexer.mockResolvedValueOnce({ + data: [ + { + name: 'twitter', + totalStake: '0', + selfStake: '0', + validatorWeight: '0', + address: 'lsk3j2dfuw4rsfsbcftwy838hd9vagmu2emype9do', + publicKey: '750b2fa94026d29b8ef49d8e00ceb1b0d31107914e327d3c8f45d61b6afef370', + }, + ], + meta: {}, + }); + + const { checkIfAccountIsValidator } = require('../../../../shared/helpers/account'); + + const isAccountValidator = await checkIfAccountIsValidator( + 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + ); + expect(isAccountValidator).toEqual(true); + }); + + it('should return false when account is not a validator', async () => { + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestIndexer } = require(mockedRequestFilePath); + requestIndexer.mockResolvedValueOnce({ + data: [], + meta: {}, + }); + + const { checkIfAccountIsValidator } = require('../../../../shared/helpers/account'); + + const isAccountValidator = await checkIfAccountIsValidator( + 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + ); + expect(isAccountValidator).toEqual(false); + }); + }); + + describe('Test getOpeningBalances method', () => { + it('should return opening balances when called with valid address', async () => { + const mockUserSubstore = [ + { + address: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + availableBalance: '100000000000000', + lockedBalances: [], + tokenID: '0400000000000000', + }, + ]; jest.mock(mockedRequestFilePath); // eslint-disable-next-line import/no-dynamic-require const { requestConnector } = require(mockedRequestFilePath); requestConnector.mockResolvedValueOnce(undefined).mockResolvedValueOnce(mockUserSubstore); - const { getOpeningBalance } = require('../../../../shared/helpers/account'); + const { getOpeningBalances } = require('../../../../shared/helpers/account'); - const openingBalance = await getOpeningBalance('lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo'); - const expectedResponse = { - tokenID: '0400000000000000', - amount: '100000000000000', - }; + const openingBalance = await getOpeningBalances('lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo'); + const expectedResponse = [ + { + tokenID: '0400000000000000', + amount: '100000000000000', + }, + ]; expect(openingBalance).toEqual(expectedResponse); }); it('should throw error when called with undefined', async () => { - jest.mock(mockedRequestFilePath, () => { - const actual = jest.requireActual(mockedRequestFilePath); - return { - ...actual, - requestConnector() { - return undefined; - }, - }; + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestConnector } = require(mockedRequestFilePath); + requestConnector.mockResolvedValueOnce(undefined); + + const { getOpeningBalances } = require('../../../../shared/helpers/account'); + expect(getOpeningBalances(undefined)).rejects.toThrow(); + }); + }); + + describe('Test getTokenBalancesAtGenesis method', () => { + xit('should return token balances at genesis', async () => { + const mockUserSubstore = [ + { + address: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + availableBalance: '100000000000000', + lockedBalances: [], + tokenID: '0400000000000000', + }, + ]; + + jest.mock(mockedRequestFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestConnector } = require(mockedRequestFilePath); + requestConnector.mockResolvedValueOnce({ + token: { + userSubstore: 1, + }, }); - const { getOpeningBalance } = require('../../../../shared/helpers/account'); - expect(getOpeningBalance(undefined)).rejects.toThrow(); + jest.mock(mockedRequestAllFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { requestAllCustom } = require(mockedRequestAllFilePath); + await requestAllCustom.mockReturnValue({ userSubstore: mockUserSubstore }); + + const { getTokenBalancesAtGenesis } = require('../../../../shared/helpers/account'); + + const tokenBalances = await getTokenBalancesAtGenesis(); + const expectedResponse = [{ amount: '100000000000000', tokenID: '0400000000000000' }]; + + expect(tokenBalances).toEqual(expectedResponse); }); }); }); diff --git a/services/export/tests/unit/shared/helpers/chain.test.js b/services/export/tests/unit/shared/helpers/chain.test.js index 381e889295..2c45aa7914 100644 --- a/services/export/tests/unit/shared/helpers/chain.test.js +++ b/services/export/tests/unit/shared/helpers/chain.test.js @@ -86,7 +86,7 @@ describe('Test resolveChainIDs method', () => { expect(response).toEqual(expectedResponse); }); - it('should return empty object when called with non-token transferCrossChain transaction', async () => { + xit('should return empty object when called with non-token transferCrossChain transaction', async () => { const response = resolveChainIDs(transactions.stake, chainID); expect(Object.getOwnPropertyNames(response).length).toBe(0); }); diff --git a/services/export/tests/unit/shared/helpers/file.test.js b/services/export/tests/unit/shared/helpers/file.test.js index e4c3821584..2a856c196a 100644 --- a/services/export/tests/unit/shared/helpers/file.test.js +++ b/services/export/tests/unit/shared/helpers/file.test.js @@ -18,27 +18,16 @@ const fs = require('fs'); const { interval } = require('../../../constants/csvExport'); const { dynamicFieldsCustomDelimiter } = require('../../../constants/csv'); -const { - init, - write, - read, - remove, - list, - purge, - fileExists, - isFile, - isFilePathInDirectory, - - getPartialFilenameFromParams, - getExcelFilenameFromParams, - getExcelFileUrlFromParams, -} = require('../../../../shared/helpers/file'); const { PARTIAL_FILENAME, EXCEL_EXPORT_FILENAME, EXCEL_FILE_URL, } = require('../../../../shared/regex'); +const mockedChainFilePath = path.resolve(`${__dirname}/../../../../shared/helpers/chain`); + +beforeEach(() => jest.resetModules()); + describe('Test filesystem interface', () => { let dirPath; const testData = dynamicFieldsCustomDelimiter.expectedCsv; @@ -54,12 +43,15 @@ describe('Test filesystem interface', () => { }); it('should create a directory when calling init() method', async () => { + const { init, fileExists } = require('../../../../shared/helpers/file'); + await init({ dirPath }); const isExists = await fileExists(dirPath); expect(isExists).toBe(true); }); it('should write data to a file when calling write() method', async () => { + const { write } = require('../../../../shared/helpers/file'); const filePath = `${dirPath}/testfile.csv`; // Write data into the file @@ -72,6 +64,8 @@ describe('Test filesystem interface', () => { it('should return the data from a file when calling read() method', async () => { const filePath = `${dirPath}/testfile.csv`; + const { read } = require('../../../../shared/helpers/file'); + // Read data from file const result = await read(filePath); expect(result).toEqual(testData); @@ -79,6 +73,7 @@ describe('Test filesystem interface', () => { it('should remove a file when calling remove() method', async () => { const filePath = `${dirPath}/testfile.csv`; + const { remove, fileExists } = require('../../../../shared/helpers/file'); let isExists = await fileExists(filePath); expect(isExists).toBe(true); @@ -91,6 +86,8 @@ describe('Test filesystem interface', () => { const filePath1 = `${dirPath}/testfile1.csv`; const filePath2 = `${dirPath}/testfile2.csv`; + const { write, list } = require('../../../../shared/helpers/file'); + await write(filePath1, testData); await write(filePath2, testData); @@ -99,6 +96,7 @@ describe('Test filesystem interface', () => { }); it('should return false for a directory when calling isFile() method', async () => { + const { write, isFile } = require('../../../../shared/helpers/file'); expect(await isFile(dirPath)).toBe(false); const filePath = `${dirPath}/testfile.csv`; @@ -107,6 +105,7 @@ describe('Test filesystem interface', () => { }); it('should throw error when calling purge() method when path is null', async () => { + const { list, purge } = require('../../../../shared/helpers/file'); const files = await list(dirPath); expect(files.length).toBe(3); @@ -114,6 +113,7 @@ describe('Test filesystem interface', () => { }); it('should remove all files in a directory when calling purge() method', async () => { + const { list, purge } = require('../../../../shared/helpers/file'); let files = await list(dirPath); expect(files.length).toBe(3); @@ -124,6 +124,7 @@ describe('Test filesystem interface', () => { }); it('should return true for file path within the directory', () => { + const { isFilePathInDirectory } = require('../../../../shared/helpers/file'); const filePath = `${dirPath}/testfile.csv`; const result = isFilePathInDirectory(filePath, dirPath); expect(result).toBe(true); @@ -131,6 +132,7 @@ describe('Test filesystem interface', () => { it('should return false for file path outside the directory', () => { const filePath = `${dirPath}/../../testfile.csv`; + const { isFilePathInDirectory } = require('../../../../shared/helpers/file'); const result = isFilePathInDirectory(filePath, dirPath); expect(result).toBe(false); }); @@ -143,6 +145,7 @@ describe('Test getPartialFilenameFromParams method', () => { it('should return partial filename when called with address', async () => { const params = { address, interval: interval.startEnd }; + const { getPartialFilenameFromParams } = require('../../../../shared/helpers/file'); const partialFilename = await getPartialFilenameFromParams(params, interval.onlyStart); expect(partialFilename.endsWith(partialFilenameExtension)).toBeTruthy(); expect(partialFilename).toContain(address); @@ -151,6 +154,7 @@ describe('Test getPartialFilenameFromParams method', () => { it('should return partial filename when called with publicKey', async () => { const params = { publicKey, interval: interval.onlyStart }; + const { getPartialFilenameFromParams } = require('../../../../shared/helpers/file'); const partialFilename = await getPartialFilenameFromParams(params, interval.onlyStart); expect(partialFilename.endsWith(partialFilenameExtension)).toBeTruthy(); expect(partialFilename).toContain(address); @@ -161,13 +165,15 @@ describe('Test getPartialFilenameFromParams method', () => { describe('Excel export utils', () => { const address = 'lskeqretdgm6855pqnnz69ahpojk5yxfsv2am34et'; const publicKey = 'b7fdfc991c52ad6646159506a8326d4203c868bd3f16b8043c8e4e034346e581'; + const chainID = '00000000'; const excelFilenameExtension = '.xlsx'; const excelFileUrlBeginsWith = '/api/v3/export/'; describe('Test getExcelFilenameFromParams method', () => { it('should return excel filename when called with address and complete interval with start and end date supplied', async () => { const params = { address, interval: interval.startEnd }; - const excelFilename = await getExcelFilenameFromParams(params); + const { getExcelFilenameFromParams } = require('../../../../shared/helpers/file'); + const excelFilename = await getExcelFilenameFromParams(params, chainID); expect(excelFilename.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilename).toContain(address); expect(excelFilename).toMatch(EXCEL_EXPORT_FILENAME); @@ -175,7 +181,8 @@ describe('Excel export utils', () => { it('should return excel filename when called with publicKey and complete interval with start and end date supplied', async () => { const params = { publicKey, interval: interval.startEnd }; - const excelFilename = await getExcelFilenameFromParams(params); + const { getExcelFilenameFromParams } = require('../../../../shared/helpers/file'); + const excelFilename = await getExcelFilenameFromParams(params, chainID); expect(excelFilename.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilename).toContain(address); expect(excelFilename).toMatch(EXCEL_EXPORT_FILENAME); @@ -183,7 +190,8 @@ describe('Excel export utils', () => { it('should return excel filename when called with address and interval with only start date supplied', async () => { const params = { address, interval: interval.onlyStart }; - const excelFilename = await getExcelFilenameFromParams(params); + const { getExcelFilenameFromParams } = require('../../../../shared/helpers/file'); + const excelFilename = await getExcelFilenameFromParams(params, chainID); expect(excelFilename.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilename).toContain(address); expect(excelFilename).toMatch(EXCEL_EXPORT_FILENAME); @@ -191,7 +199,8 @@ describe('Excel export utils', () => { it('should return excel filename when called with publicKey and interval with only start date supplied', async () => { const params = { publicKey, interval: interval.onlyStart }; - const excelFilename = await getExcelFilenameFromParams(params); + const { getExcelFilenameFromParams } = require('../../../../shared/helpers/file'); + const excelFilename = await getExcelFilenameFromParams(params, chainID); expect(excelFilename.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilename).toContain(address); expect(excelFilename).toMatch(EXCEL_EXPORT_FILENAME); @@ -199,7 +208,8 @@ describe('Excel export utils', () => { xit('should return excel filename when called with address and no interval supplied', async () => { const params = { address }; - const excelFilename = await getExcelFilenameFromParams(params); + const { getExcelFilenameFromParams } = require('../../../../shared/helpers/file'); + const excelFilename = await getExcelFilenameFromParams(params, chainID); expect(excelFilename.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilename).toContain(address); expect(excelFilename).toMatch(EXCEL_EXPORT_FILENAME); @@ -207,7 +217,8 @@ describe('Excel export utils', () => { xit('should return excel filename when called with publicKey and no interval supplied', async () => { const params = { publicKey }; - const excelFilename = await getExcelFilenameFromParams(params); + const { getExcelFilenameFromParams } = require('../../../../shared/helpers/file'); + const excelFilename = await getExcelFilenameFromParams(params, chainID); expect(excelFilename.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilename).toContain(address); expect(excelFilename).toMatch(EXCEL_EXPORT_FILENAME); @@ -217,7 +228,8 @@ describe('Excel export utils', () => { describe('Test getExcelFileUrlFromParams method', () => { it('should return excel filepath URL when called with address and complete interval with start and end date supplied', async () => { const params = { address, interval: interval.startEnd }; - const excelFilepathUrl = await getExcelFileUrlFromParams(params); + const { getExcelFileUrlFromParams } = require('../../../../shared/helpers/file'); + const excelFilepathUrl = await getExcelFileUrlFromParams(params, chainID); expect(excelFilepathUrl.startsWith(excelFileUrlBeginsWith)).toBeTruthy(); expect(excelFilepathUrl.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilepathUrl).toContain(address); @@ -226,7 +238,8 @@ describe('Excel export utils', () => { it('should return excel filepath URL when called with publicKey and complete interval with start and end date supplied', async () => { const params = { publicKey, interval: interval.startEnd }; - const excelFilepathUrl = await getExcelFileUrlFromParams(params); + const { getExcelFileUrlFromParams } = require('../../../../shared/helpers/file'); + const excelFilepathUrl = await getExcelFileUrlFromParams(params, chainID); expect(excelFilepathUrl.startsWith(excelFileUrlBeginsWith)).toBeTruthy(); expect(excelFilepathUrl.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilepathUrl).toContain(address); @@ -235,7 +248,8 @@ describe('Excel export utils', () => { it('should return excel filepath URL when called with address and interval with only start date supplied', async () => { const params = { address, interval: interval.onlyStart }; - const excelFilepathUrl = await getExcelFileUrlFromParams(params); + const { getExcelFileUrlFromParams } = require('../../../../shared/helpers/file'); + const excelFilepathUrl = await getExcelFileUrlFromParams(params, chainID); expect(excelFilepathUrl.startsWith(excelFileUrlBeginsWith)).toBeTruthy(); expect(excelFilepathUrl.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilepathUrl).toContain(address); @@ -244,25 +258,66 @@ describe('Excel export utils', () => { it('should return excel filepath URL when called with publicKey and interval with only start date supplied', async () => { const params = { publicKey, interval: interval.onlyStart }; - const excelFilepathUrl = await getExcelFileUrlFromParams(params); + const { getExcelFileUrlFromParams } = require('../../../../shared/helpers/file'); + const excelFilepathUrl = await getExcelFileUrlFromParams(params, chainID); expect(excelFilepathUrl.startsWith(excelFileUrlBeginsWith)).toBeTruthy(); expect(excelFilepathUrl.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilepathUrl).toContain(address); expect(excelFilepathUrl).toMatch(EXCEL_FILE_URL); }); - xit('should return excel filepath URL when called with address and no interval supplied', async () => { + it('should return excel filepath URL when called with address and no interval supplied', async () => { const params = { address }; - const excelFilepathUrl = await getExcelFileUrlFromParams(params); + + jest.mock(mockedChainFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { getNetworkStatus, getBlocks } = require(mockedChainFilePath); + getNetworkStatus.mockResolvedValueOnce({ + data: { + genesisHeight: 1, + }, + }); + + getBlocks.mockResolvedValueOnce({ + data: [ + { + timestamp: 1704198870, + }, + ], + }); + + const { getExcelFileUrlFromParams } = require('../../../../shared/helpers/file'); + + const excelFilepathUrl = await getExcelFileUrlFromParams(params, chainID); expect(excelFilepathUrl.startsWith(excelFileUrlBeginsWith)).toBeTruthy(); expect(excelFilepathUrl.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilepathUrl).toContain(address); expect(excelFilepathUrl).toMatch(EXCEL_FILE_URL); }); - xit('should return excel filepath URL when called with publicKey and no interval supplied', async () => { + it('should return excel filepath URL when called with publicKey and no interval supplied', async () => { const params = { publicKey }; - const excelFilepathUrl = await getExcelFileUrlFromParams(params); + + jest.mock(mockedChainFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { getNetworkStatus, getBlocks } = require(mockedChainFilePath); + getNetworkStatus.mockResolvedValueOnce({ + data: { + genesisHeight: 1, + }, + }); + + getBlocks.mockResolvedValueOnce({ + data: [ + { + timestamp: 1704198870, + }, + ], + }); + + const { getExcelFileUrlFromParams } = require('../../../../shared/helpers/file'); + + const excelFilepathUrl = await getExcelFileUrlFromParams(params, chainID); expect(excelFilepathUrl.startsWith(excelFileUrlBeginsWith)).toBeTruthy(); expect(excelFilepathUrl.endsWith(excelFilenameExtension)).toBeTruthy(); expect(excelFilepathUrl).toContain(address); diff --git a/services/export/tests/unit/shared/helpers/time.test.js b/services/export/tests/unit/shared/helpers/time.test.js index 5585e319bf..2594cf37ba 100644 --- a/services/export/tests/unit/shared/helpers/time.test.js +++ b/services/export/tests/unit/shared/helpers/time.test.js @@ -13,6 +13,7 @@ * Removal or modification of this copyright notice is prohibited. * */ +const { resolve } = require('path'); const moment = require('moment'); const config = require('../../../../config'); @@ -20,20 +21,20 @@ const config = require('../../../../config'); const { interval } = require('../../../constants/csvExport'); const { STANDARDIZED_INTERVAL } = require('../../../../shared/regex'); const { timestamp, expectedDate, expectedTime } = require('../../../constants/time'); -const { - dateFromTimestamp, - timeFromTimestamp, - getToday, - standardizeIntervalFromParams, -} = require('../../../../shared/helpers/time'); + +const mockedChainFilePath = resolve(`${__dirname}/../../../../shared/helpers/chain`); + +beforeEach(() => jest.resetModules()); describe('Time utils', () => { it('returns ISO format UTC Date from unix timestamp', async () => { + const { dateFromTimestamp } = require('../../../../shared/helpers/time'); const date = dateFromTimestamp(timestamp); expect(date).toBe(expectedDate); }); it('returns ISO format UTC Time from unix timestamp', async () => { + const { timeFromTimestamp } = require('../../../../shared/helpers/time'); const time = timeFromTimestamp(timestamp); expect(time).toBe(expectedTime); }); @@ -41,6 +42,7 @@ describe('Time utils', () => { describe('Test getToday method', () => { it(`should return current date in '${config.excel.dateFormat}' format`, async () => { + const { getToday } = require('../../../../shared/helpers/time'); const today = getToday(); expect(today).toBe(moment().format(config.excel.dateFormat)); }); @@ -48,6 +50,7 @@ describe('Test getToday method', () => { describe('Test standardizeIntervalFromParams method', () => { it('should return standardized interval when both start and end date supplied', async () => { + const { standardizeIntervalFromParams } = require('../../../../shared/helpers/time'); const result = await standardizeIntervalFromParams({ interval: interval.startEnd }); expect(typeof result).toBe('string'); expect(result.length).toBe(2 * config.excel.dateFormat.length + 1); @@ -55,13 +58,32 @@ describe('Test standardizeIntervalFromParams method', () => { }); it('should return standardized interval when only start date supplied', async () => { + const { standardizeIntervalFromParams } = require('../../../../shared/helpers/time'); const result = await standardizeIntervalFromParams({ interval: interval.onlyStart }); expect(typeof result).toBe('string'); expect(result.length).toBe(2 * config.excel.dateFormat.length + 1); expect(result).toMatch(STANDARDIZED_INTERVAL); }); - xit('should return standardized interval when dates not supplied', async () => { + it('should return standardized interval when dates not supplied', async () => { + jest.mock(mockedChainFilePath); + // eslint-disable-next-line import/no-dynamic-require + const { getNetworkStatus, getBlocks } = require(mockedChainFilePath); + getNetworkStatus.mockResolvedValueOnce({ + data: { + genesisHeight: 1, + }, + }); + + getBlocks.mockResolvedValueOnce({ + data: [ + { + timestamp: 1704198870, + }, + ], + }); + + const { standardizeIntervalFromParams } = require('../../../../shared/helpers/time'); const result = await standardizeIntervalFromParams({}); expect(typeof result).toBe('string'); expect(result.length).toBe(2 * config.excel.dateFormat.length + 1); diff --git a/services/export/tests/unit/shared/helpers/transaction.test.js b/services/export/tests/unit/shared/helpers/transaction.test.js index 2d6bfa33ab..532a7fcdd9 100644 --- a/services/export/tests/unit/shared/helpers/transaction.test.js +++ b/services/export/tests/unit/shared/helpers/transaction.test.js @@ -97,7 +97,7 @@ describe('Test Transaction utility', () => { expect(fee).not.toBeNull(); expect(typeof fee).toBe('string'); - expect(fee).toBe(transactions.reclaim.fee); + expect(fee).toBe(String(-transactions.reclaim.fee)); }); it('should return 0 fees for a token transfer credit', async () => { @@ -119,7 +119,7 @@ describe('Test Transaction utility', () => { expect(fee).not.toBeNull(); expect(typeof fee).toBe('string'); - expect(fee).toBe(transactions.tokenTransfer.fee); + expect(fee).toBe(String(-transactions.tokenTransfer.fee)); }); }); diff --git a/services/export/tests/unit/shared/transactionsExport.test.js b/services/export/tests/unit/shared/transactionsExport.test.js index b54fd33b4d..e0fa111c95 100644 --- a/services/export/tests/unit/shared/transactionsExport.test.js +++ b/services/export/tests/unit/shared/transactionsExport.test.js @@ -20,14 +20,14 @@ const { resolve } = require('path'); const { tokenTransfer } = require('../../constants/csvExport'); const { blocks } = require('../../constants/blocks'); +const { events } = require('../../constants/events'); +const { transactions } = require('../../constants/transaction'); const fieldMappings = require('../../../shared/excelFieldMappings'); const { dateFromTimestamp, timeFromTimestamp } = require('../../../shared/helpers/time'); -const { formatTransaction, formatBlocks } = require('../../../shared/transactionsExport'); const mockedRequestFilePath = resolve(`${__dirname}/../../../shared/helpers/request`); -const mockedRequestAllFilePath = resolve(`${__dirname}/../../../shared/helpers/requestAll`); jest.mock('lisk-service-framework', () => { const actualLiskServiceFramework = jest.requireActual('lisk-service-framework'); @@ -44,7 +44,10 @@ jest.mock('lisk-service-framework', () => { }, }, CacheRedis: jest.fn(), - CacheLRU: jest.fn(), + CacheLRU: jest.fn(() => ({ + set: jest.fn(), + get: jest.fn(), + })), Queue: jest.fn(), }; }); @@ -54,142 +57,209 @@ beforeEach(() => jest.resetModules()); const chainID = '04000000'; const txFeeTokenID = '0400000000000000'; -describe('Test getCCTransferTransactionInfo method', () => { - it('should return transaction info when called with valid address (event topic contains transaction prefix)', async () => { - const mockEventData = [ +describe('Test formatTransaction method', () => { + it('should return a transaction normalized', async () => { + const { formatTransaction } = require('../../../shared/transactionsExport'); + + const formattedTx = await formatTransaction( + tokenTransfer.toOther.sender, + tokenTransfer.toOther.transaction, + chainID, + txFeeTokenID, + ); + const expectedFields = Object.values(fieldMappings.transactionMappings).map(v => + v.key !== 'blockReward' ? v.key : undefined, + ); + expect(Object.keys(formattedTx)).toEqual(expect.arrayContaining(expectedFields.filter(e => e))); + }); +}); + +describe('Test formatBlocks method', () => { + it('should return a blocks normalized when called with valid blocks', async () => { + const { formatBlocks } = require('../../../shared/transactionsExport'); + + const normalizedBlocks = await formatBlocks(blocks); + const expectedResponse = [ { - id: 'efe94d3a5ad35297098614100c5dd7bff6657d38baed08fb850fa9ce69b0862c', - module: 'token', - name: 'ccmTransfer', - data: { - senderAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - tokenID: '0400000000000000', - amount: '100000000000', - receivingChainID: '04000001', - result: 0, - }, - topics: [ - '04efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - ], - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, + blockHeight: blocks[0].height, + blockReward: blocks[0].reward, + date: dateFromTimestamp(blocks[0].timestamp), + time: timeFromTimestamp(blocks[0].timestamp), + }, + { + blockHeight: blocks[1].height, + blockReward: blocks[1].reward, + date: dateFromTimestamp(blocks[1].timestamp), + time: timeFromTimestamp(blocks[1].timestamp), + }, + { + blockHeight: blocks[2].height, + blockReward: blocks[2].reward, + date: dateFromTimestamp(blocks[2].timestamp), + time: timeFromTimestamp(blocks[2].timestamp), }, ]; + expect(normalizedBlocks).toEqual(expectedResponse); + }); - jest.mock(mockedRequestAllFilePath, () => { - const actual = jest.requireActual(mockedRequestAllFilePath); - return { - ...actual, - requestAllStandard() { - return mockEventData; - }, - }; - }); + it('should throw error when called with null', async () => { + const { formatBlocks } = require('../../../shared/transactionsExport'); + expect(formatBlocks(null)).rejects.toThrow(); + }); + it('should throw error when called with undefined', async () => { + const { formatBlocks } = require('../../../shared/transactionsExport'); + expect(formatBlocks(undefined)).rejects.toThrow(); + }); +}); + +describe('Test getBlockRewardEntries method', () => { + const address = 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo'; + it('should return block reward entries when token minted', async () => { jest.mock(mockedRequestFilePath, () => { const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, + requestConnector() { + return { + posTokenID: '0400000000000000', + }; + }, requestIndexer() { return { - data: [ - { - moduleCommand: 'interoperability:submitSidechainCrossChainUpdate', - params: { sendingChainID: '04000000' }, - }, - ], + data: { + chainID: '04000000', + }, }; }, }; }); - const { getCCTransferTransactionInfo } = require('../../../shared/transactionsExport'); + const { getBlockRewardEntries } = require('../../../shared/transactionsExport'); - const crossChainTransferTxs = await getCCTransferTransactionInfo({ - address: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - }); - const expectedResponse = [ + const blockRewardEntries = await getBlockRewardEntries( + address, + events.tokenMintedEvent, + null, + blocks[0], + ); + + const expectedResult = [ { - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, - id: 'efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - isIncomingCrossChainTransferTransaction: true, - moduleCommand: 'interoperability:submitSidechainCrossChainUpdate', - params: { - amount: '100000000000', - data: "This entry was generated from 'ccmTransfer' event emitted from the specified CCU transactionID.", - receivingChainID: '04000001', - recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - result: 0, - senderAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - tokenID: '0400000000000000', - }, - sender: { - address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - }, + amount: '161000', + amountTokenID: '0400000000000000', + blockHeight: 15, + date: '2022-11-17', + fee: null, + moduleCommand: null, + note: 'Block generation reward (commission + self-stake)', + receivingChainID: '04000000', + recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + recipientPublicKey: '7fb87fd7fdfef8037d9b6ca705d17000b9f639b4c7aa6f13383d178c783bbdfd', + senderAddress: null, + senderPublicKey: null, sendingChainID: '04000000', + time: '11:52:28', + transactionID: null, + txFeeTokenID: null, }, ]; - expect(crossChainTransferTxs).toEqual(expectedResponse); + expect(blockRewardEntries).toHaveLength(1); + expect(blockRewardEntries).toEqual(expectedResult); }); - it('should return transaction info when called with valid address (event topic does not contain transaction prefix)', async () => { - const mockEventData = [ - { - id: 'efe94d3a5ad35297098614100c5dd7bff6657d38baed08fb850fa9ce69b0862c', - module: 'token', - name: 'ccmTransfer', - data: { - senderAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - tokenID: '0400000000000000', - amount: '100000000000', - receivingChainID: '04000001', - result: 0, - }, - topics: [ - 'efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - ], - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, - }, - ]; - - jest.mock(mockedRequestAllFilePath, () => { - const actual = jest.requireActual(mockedRequestAllFilePath); + it('should return block reward entries when token minted and locked', async () => { + jest.mock(mockedRequestFilePath, () => { + const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, - requestAllStandard() { - return mockEventData; + requestConnector() { + return { + posTokenID: '0400000000000000', + }; + }, + requestIndexer() { + return { + data: { + chainID: '04000000', + }, + }; }, }; }); + const { getBlockRewardEntries } = require('../../../shared/transactionsExport'); + + const blockRewardEntries = await getBlockRewardEntries( + address, + events.tokenMintedEvent, + events.tokenLockedEvent, + blocks[0], + ); + const expectedResult = [ + { + amount: '30000', + amountTokenID: '0400000000000000', + blockHeight: 15, + date: '2022-11-17', + fee: null, + moduleCommand: null, + note: 'Block generation reward (commission + self-stake)', + receivingChainID: '04000000', + recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + recipientPublicKey: '7fb87fd7fdfef8037d9b6ca705d17000b9f639b4c7aa6f13383d178c783bbdfd', + senderAddress: null, + senderPublicKey: null, + sendingChainID: '04000000', + time: '11:52:28', + transactionID: null, + txFeeTokenID: null, + }, + { + amount: '131000', + amountTokenID: '0400000000000000', + blockHeight: 15, + date: '2022-11-17', + fee: null, + moduleCommand: null, + note: 'Block generation reward (custodial shared rewards locked)', + receivingChainID: '04000000', + recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', + recipientPublicKey: '7fb87fd7fdfef8037d9b6ca705d17000b9f639b4c7aa6f13383d178c783bbdfd', + senderAddress: null, + senderPublicKey: null, + sendingChainID: '04000000', + time: '11:52:28', + transactionID: null, + txFeeTokenID: null, + }, + ]; + + expect(blockRewardEntries).toHaveLength(2); + expect(blockRewardEntries).toEqual(expectedResult); + }); +}); + +describe('Test getChainInfo method', () => { + it('should return chain info when called with valid chainID', async () => { + const validChainID = '04000000'; + jest.mock(mockedRequestFilePath, () => { const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, - requestIndexer() { + requestAppRegistry() { return { data: [ { - moduleCommand: 'interoperability:submitSidechainCrossChainUpdate', - params: { sendingChainID: '04000000' }, + chainName: 'lisk_mainchain', + displayName: 'Lisk', + chainID: '04000000', + title: 'Lisk - Devnet', + description: 'Metadata configuration for the Lisk blockchain (mainchain) in devnet', + networkType: 'devnet', + isDefault: true, }, ], }; @@ -197,305 +267,324 @@ describe('Test getCCTransferTransactionInfo method', () => { }; }); - const { getCCTransferTransactionInfo } = require('../../../shared/transactionsExport'); + const { getChainInfo } = require('../../../shared/transactionsExport'); - const crossChainTransferTxs = await getCCTransferTransactionInfo({ - address: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - }); - const expectedResponse = [ - { - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, - id: 'efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - isIncomingCrossChainTransferTransaction: true, - moduleCommand: 'interoperability:submitSidechainCrossChainUpdate', - params: { - amount: '100000000000', - data: "This entry was generated from 'ccmTransfer' event emitted from the specified CCU transactionID.", - receivingChainID: '04000001', - recipientAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - result: 0, - senderAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - tokenID: '0400000000000000', - }, - sender: { - address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - }, - sendingChainID: '04000000', - }, - ]; - - expect(crossChainTransferTxs).toEqual(expectedResponse); + const chainInfo = await getChainInfo(validChainID); + const expectedResponse = { + chainName: 'lisk_mainchain', + chainID: '04000000', + }; + expect(chainInfo).toEqual(expectedResponse); }); +}); - it('should throw error when called with undefined', async () => { +describe('Test getGeneratorFeeEntries method', () => { + const address = 'lskme8ohf9geuno8nwpvdqm8wr8bvz5nzguftwpxp'; + it('should return generator fee reward entries', async () => { jest.mock(mockedRequestFilePath, () => { const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, + requestConnector() { + return '0400000000000000'; + }, requestIndexer() { - return undefined; + return { + data: { + chainID: '04000000', + }, + }; }, }; }); - const { getCCTransferTransactionInfo } = require('../../../shared/transactionsExport'); - expect(getCCTransferTransactionInfo(undefined)).rejects.toThrow(); - }); -}); + const { getGeneratorFeeEntries } = require('../../../shared/transactionsExport'); + + const generatorFeeEntries = await getGeneratorFeeEntries( + address, + events.genFeeProcessed, + transactions.tokenTransfer, + blocks[0], + ); -describe('Test getRewardAssignedInfo method', () => { - it('should return reward assigned info when called with valid address (event topic contains transaction prefix)', async () => { - const mockEventData = [ + const expectedResult = [ { - id: 'efe94d3a5ad35297098614100c5dd7bff6657d38baed08fb850fa9ce69b0862c', - module: 'pos', - name: 'rewardsAssigned', - data: { - stakerAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - validatorAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - tokenID: '0400000000000000', - amount: '100000000000', - result: 0, - }, - topics: [ - '04efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - ], - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, + amount: '21000', + amountTokenID: '0400000000000000', + blockHeight: 15, + date: '2022-11-17', + fee: null, + moduleCommand: null, + note: 'Generator Fee', + receivingChainID: '04000000', + recipientAddress: 'lskme8ohf9geuno8nwpvdqm8wr8bvz5nzguftwpxp', + recipientPublicKey: null, + senderAddress: 'lskmv6entvj8cnrhfdoa38ojx34pv4rd9q44788r7', + senderPublicKey: '1a315a7c7ccfb44ee0730f22cac4370307a7ef29710b938cff52e653cac753ad', + sendingChainID: '04000000', + time: '11:52:28', + transactionID: 'd41e8fbb909fdf44ffccef6f5b0fb5edf853f0dcf699243a0a92403d2a4f1d1d', + txFeeTokenID: null, }, ]; - jest.mock(mockedRequestAllFilePath, () => { - const actual = jest.requireActual(mockedRequestAllFilePath); - return { - ...actual, - requestAllStandard() { - return mockEventData; - }, - }; - }); + expect(generatorFeeEntries).toEqual(expectedResult); + }); +}); +describe('Test getSharedRewardsAssignedEntries method', () => { + const address = 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo'; + it('should return shared reward entries', async () => { jest.mock(mockedRequestFilePath, () => { const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, + requestConnector() { + return { + posTokenID: '0400000000000000', + }; + }, requestIndexer() { return { - data: [ - { - moduleCommand: 'pos:stake', - params: { - stakes: [ - { - validatorAddress: 'lskkdvzyxhvm2kmgs8hmteaad2zrjbjmf4cft9zpp', - amount: '-1000000000', - }, - { - validatorAddress: 'lsk64zamp63e9km9p6vtfea9c5pda2wuw79tc8a9k', - amount: '2000000000', - }, - ], - }, - }, - ], + data: { + chainID: '04000000', + }, }; }, }; }); - const { getRewardAssignedInfo } = require('../../../shared/transactionsExport'); + const { getSharedRewardsAssignedEntries } = require('../../../shared/transactionsExport'); - const rewardsAssignedInfo = await getRewardAssignedInfo({ - address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - }); - const expectedResponse = [ + const sharedRewardsAssignedEntries = await getSharedRewardsAssignedEntries( + address, + events.rewardsAssigned, + transactions.claimedRewards, + blocks[0], + ); + + const expectedResult = [ { - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, - id: 'efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - moduleCommand: 'pos:stake', - params: { - amount: '100000000000', - data: "This entry was generated from 'rewardsAssigned' event emitted from the specified transactionID.", - validatorAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - result: 0, - stakerAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - tokenID: '0400000000000000', - }, - sender: { - address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - }, - rewardAmount: '100000000000', - rewardTokenID: '0400000000000000', + amount: '-87694485125', + amountTokenID: '0400000000000000', + blockHeight: 15, + date: '2022-11-17', + fee: null, + moduleCommand: null, + note: 'Custodial shared rewards transfer to the staker', + receivingChainID: '04000000', + recipientAddress: 'lskmg3sdmjp4smz6x9k2cuyuwags5ehgtexe4w2ds', + recipientPublicKey: 'f0fda0461215e4e63a68d12c79d293833c32519cfe3a5e01ca08b0a0a7493de5', + senderAddress: 'lsk26s9p9rb74ygzxayuf9cx6x7x5wuvp2v9yrns7', + senderPublicKey: null, + sendingChainID: '04000000', + time: '11:52:28', + transactionID: '732923c6e8780251c1dcd179e3e657827ae9318a6df920de595d743f1ed70a40', + txFeeTokenID: null, }, ]; - expect(rewardsAssignedInfo).toEqual(expectedResponse); + expect(sharedRewardsAssignedEntries).toEqual(expectedResult); }); +}); - it('should return reward assigned info when called with valid address (event topic does not contain transaction prefix)', async () => { - const mockEventData = [ - { - id: 'efe94d3a5ad35297098614100c5dd7bff6657d38baed08fb850fa9ce69b0862c', - module: 'pos', - name: 'rewardsAssigned', - data: { - stakerAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - validatorAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - tokenID: '0400000000000000', - amount: '100000000000', - result: 0, - }, - topics: [ - 'efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - ], - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, - }, - ]; - - jest.mock(mockedRequestAllFilePath, () => { - const actual = jest.requireActual(mockedRequestAllFilePath); - return { - ...actual, - requestAllStandard() { - return mockEventData; - }, - }; - }); +// Verify implementation +describe('Test getMessageFeeEntries method', () => { + const address = 'lskme8ohf9geuno8nwpvdqm8wr8bvz5nzguftwpxp'; + const sendingChainID = '04000000'; + const receivingChainID = '04000000'; + const messageFeeTokenID = '0400000000000000'; + it('should return medssage fee entries', async () => { jest.mock(mockedRequestFilePath, () => { const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, + requestConnector() { + return '0400000000000000'; + }, requestIndexer() { return { - data: [ - { - moduleCommand: 'pos:stake', - params: { - stakes: [ - { - validatorAddress: 'lskkdvzyxhvm2kmgs8hmteaad2zrjbjmf4cft9zpp', - amount: '-1000000000', - }, - { - validatorAddress: 'lsk64zamp63e9km9p6vtfea9c5pda2wuw79tc8a9k', - amount: '2000000000', - }, - ], - }, - }, - ], + data: { + chainID: '04000000', + }, }; }, }; }); - const { getRewardAssignedInfo } = require('../../../shared/transactionsExport'); + const { getMessageFeeEntries } = require('../../../shared/transactionsExport'); - const rewardsAssignedInfo = await getRewardAssignedInfo({ - address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - }); - const expectedResponse = [ + const messageFeeEntries = await getMessageFeeEntries( + address, + events.relayerFeeProcessed, + transactions.tokenTransferCrossChain, + blocks[0], + messageFeeTokenID, + sendingChainID, + receivingChainID, + ); + + const expectedResult = [ { - block: { - id: '1fc7e1a4a06a6b9610ed5e4fb48c9f839b1fcd0f91b3f6d4c22f9f64eac40657', - height: 313, - timestamp: 1689693410, - }, - id: 'efcbab90c4769dc47029412010ef76623722678f446a7417f59fed998a6407de', - moduleCommand: 'pos:stake', - params: { - amount: '100000000000', - data: "This entry was generated from 'rewardsAssigned' event emitted from the specified transactionID.", - validatorAddress: 'lskyvvam5rxyvbvofxbdfcupxetzmqxu22phm4yuo', - result: 0, - stakerAddress: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - tokenID: '0400000000000000', - }, - sender: { - address: 'lskguo9kqnea2zsfo3a6qppozsxsg92nuuma3p7ad', - }, - rewardAmount: '100000000000', - rewardTokenID: '0400000000000000', + amount: BigInt(0), + amountTokenID: '0400000000000000', + blockHeight: 15, + date: '2022-11-17', + fee: null, + moduleCommand: 'token:transferCrossChain', + note: 'Message fee for relayer', + receivingChainID: '04000000', + recipientAddress: 'lskme8ohf9geuno8nwpvdqm8wr8bvz5nzguftwpxp', + recipientPublicKey: null, + senderAddress: null, + senderPublicKey: null, + sendingChainID: '04000000', + time: '11:52:28', + transactionID: '2ceda7b8ccfaa6c452651e6ba2e0a8acf88350aeeb0cde4da98701419e0657c6', + txFeeTokenID: null, }, ]; - expect(rewardsAssignedInfo).toEqual(expectedResponse); + expect(messageFeeEntries).toEqual(expectedResult); }); +}); - it('should throw error when called with undefined', async () => { +describe('Test getOutgoingTransferCCEntries method', () => { + const address = 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs'; + it('should return outgoing transfer cross chain entries', async () => { jest.mock(mockedRequestFilePath, () => { const actual = jest.requireActual(mockedRequestFilePath); return { ...actual, + requestConnector() { + return '0400000000000000'; + }, requestIndexer() { - return undefined; + return { + data: { + chainID: '04000000', + }, + }; }, }; }); - const { getRewardAssignedInfo } = require('../../../shared/transactionsExport'); - expect(getRewardAssignedInfo(undefined)).rejects.toThrow(); - }); -}); + const { getOutgoingTransferCCEntries } = require('../../../shared/transactionsExport'); -describe('Test formatTransaction method', () => { - it('should return a transaction normalized', async () => { - const formattedTx = await formatTransaction( - tokenTransfer.toOther.sender, - tokenTransfer.toOther.transaction, - chainID, - txFeeTokenID, + const outgoingTransferCCEntries = await getOutgoingTransferCCEntries( + address, + events.transferCrossChain, + events.ccmSendSuccess, + transactions.transferCrossChain, + blocks[2], ); - const expectedFields = Object.values(fieldMappings.transactionMappings).map(v => - v.key !== 'blockReward' ? v.key : undefined, - ); - expect(Object.keys(formattedTx)).toEqual(expect.arrayContaining(expectedFields.filter(e => e))); - }); -}); -describe('Test formatBlocks method', () => { - it('should return a blocks normalized when called with valid blocks', async () => { - const normalizedBlocks = await formatBlocks(blocks); - const expectedResponse = [ + const expectedResult = [ { - blockHeight: blocks[0].height, - blockReward: blocks[0].reward, - date: dateFromTimestamp(blocks[0].timestamp), - time: timeFromTimestamp(blocks[0].timestamp), + amount: '-100000000', + amountTokenID: '0400000000000000', + blockHeight: 21016494, + date: '2024-01-02', + fee: '-10000000', + moduleCommand: 'token:transferCrossChain', + note: '', + receivingChainID: '04000002', + recipientAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + recipientPublicKey: '344c75738c096e4bd94459fe81eba45503382181d003a9d2c8be75a2f38b49fa', + senderAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + senderPublicKey: '344c75738c096e4bd94459fe81eba45503382181d003a9d2c8be75a2f38b49fa', + sendingChainID: '04000000', + time: '12:34:30', + transactionID: '34548b99aa37a5a450712c7e3f1e13b62be872d65dd7a8c1d54859408ca4914b', + txFeeTokenID: '0400000000000000', }, { - blockHeight: blocks[1].height, - blockReward: blocks[1].reward, - date: dateFromTimestamp(blocks[1].timestamp), - time: timeFromTimestamp(blocks[1].timestamp), + amount: '-109000', + amountTokenID: '0400000000000000', + blockHeight: 21016494, + date: '2024-01-02', + fee: null, + moduleCommand: null, + note: 'Message Fee', + receivingChainID: '04000002', + recipientAddress: null, + recipientPublicKey: null, + senderAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + senderPublicKey: '344c75738c096e4bd94459fe81eba45503382181d003a9d2c8be75a2f38b49fa', + sendingChainID: '04000000', + time: '12:34:30', + transactionID: '34548b99aa37a5a450712c7e3f1e13b62be872d65dd7a8c1d54859408ca4914b', + txFeeTokenID: null, }, ]; - expect(normalizedBlocks).toEqual(expectedResponse); + + expect(outgoingTransferCCEntries).toEqual(expectedResult); }); +}); - it('should throw error when called with null', async () => { - expect(formatBlocks(null)).rejects.toThrow(); +describe('Test getIncomingTransferCCEntries method', () => { + jest.mock(mockedRequestFilePath, () => { + const actual = jest.requireActual(mockedRequestFilePath); + return { + ...actual, + requestConnector() { + return '0400000000000000'; + }, + requestIndexer() { + return { + data: { + chainID: '04000000', + }, + }; + }, + }; }); - it('should throw error when called with undefined', async () => { - expect(formatBlocks(undefined)).rejects.toThrow(); + const address = 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs'; + it('should return incoming transfer cross chain entries', async () => { + const { getIncomingTransferCCEntries } = require('../../../shared/transactionsExport'); + + const incomingTransferCCEntries = await getIncomingTransferCCEntries( + address, + events.ccmTransfer, + transactions.submitMainchainCrossChainUpdate, + blocks[2], + ); + + const expectedResult = [ + { + amount: '100000000', + amountTokenID: '0400000000000000', + blockHeight: 21016494, + date: '2024-01-02', + fee: null, + moduleCommand: null, + note: 'Incoming CCM from specified CCU transactionID', + receivingChainID: '04000002', + recipientAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + recipientPublicKey: null, + senderAddress: 'lsk56p8e53k3kar8epeqwpbxa2yd4urn8ouzhfvgs', + senderPublicKey: null, + sendingChainID: '04000000', + time: '12:34:30', + transactionID: 'd16d1cb5fa32df64988b4ab5de66b7d43c8fbfdaf043aca84d649f914d66189f', + txFeeTokenID: null, + }, + ]; + + expect(incomingTransferCCEntries).toEqual(expectedResult); + }); + + it('should return empty list when result is not successful', async () => { + const { getIncomingTransferCCEntries } = require('../../../shared/transactionsExport'); + + const incomingTransferCCEntries = await getIncomingTransferCCEntries( + address, + { ...events.ccmTransfer, data: { ...events.ccmTransfer.data, result: 1 } }, + transactions.submitMainchainCrossChainUpdate, + blocks[2], + ); + expect(incomingTransferCCEntries).toHaveLength(0); }); });