From 8e126e8ee41a8a36d6f851c357a3a5a7c8901757 Mon Sep 17 00:00:00 2001 From: Jaguar0625 Date: Mon, 15 Nov 2021 17:01:59 -0400 Subject: [PATCH] bug: fix CMC routes - total: all minted funds (initial + inflation) - circulating: total - burned (returned to nemesis) - max: maximum minted funds --- rest/resources/rest.json | 4 + rest/src/index.js | 4 +- rest/src/plugins/cmc/cmcRoutes.js | 61 +++++---- rest/src/plugins/cmc/unCirculatedAccounts.js | 65 --------- rest/test/plugins/cmc/cmcRoutes_spec.js | 133 ++++++++++++------- 5 files changed, 123 insertions(+), 144 deletions(-) delete mode 100644 rest/src/plugins/cmc/unCirculatedAccounts.js diff --git a/rest/resources/rest.json b/rest/resources/rest.json index 7be9fc85..4da42429 100644 --- a/rest/resources/rest.json +++ b/rest/resources/rest.json @@ -12,6 +12,10 @@ "allowedHosts": ["*"], "allowedMethods": ["GET", "POST", "PUT", "OPTIONS"] }, + "uncirculatingAccountPublicKeys": [ + "A4739036FD7EFED2750A51EE9D1D3113BA3F9849E0889213CED7F221B2AA1A20", + "2BF1E1F3072E3BE0CD851E4741E101E33DB19C163895F69AA890E7CF177C878C" + ], "extensions": [ "accountLink", "aggregate", diff --git a/rest/src/index.js b/rest/src/index.js index 63b426a5..6f695160 100644 --- a/rest/src/index.js +++ b/rest/src/index.js @@ -131,7 +131,9 @@ const registerRoutes = (server, db, services) => { apiNode: services.config.apiNode, websocket: services.config.websocket, numBlocksTransactionFeeStats: services.config.numBlocksTransactionFeeStats, - deployment: services.config.deployment + deployment: services.config.deployment, + + uncirculatingAccountPublicKeys: services.config.uncirculatingAccountPublicKeys }, connections: services.connectionService }; diff --git a/rest/src/plugins/cmc/cmcRoutes.js b/rest/src/plugins/cmc/cmcRoutes.js index 29f81810..762b5d55 100644 --- a/rest/src/plugins/cmc/cmcRoutes.js +++ b/rest/src/plugins/cmc/cmcRoutes.js @@ -20,66 +20,69 @@ */ const cmcUtils = require('./cmcUtils'); -const uncirculatedAddresses = require('./unCirculatedAccounts'); +const { longToUint64 } = require('../../db/dbUtils'); const routeUtils = require('../../routes/routeUtils'); -const errors = require('../../server/errors'); const AccountType = require('../AccountType'); +const catapult = require('catapult-sdk'); const ini = require('ini'); const fs = require('fs'); const util = require('util'); +const { convert, uint64 } = catapult.utils; + module.exports = { register: (server, db, services) => { const sender = routeUtils.createSender('cmc'); + const propertyValueToMosaicId = value => uint64.fromHex(value.replace(/'/g, '').replace('0x', '')); + const readAndParseNetworkPropertiesFile = () => { const readFile = util.promisify(fs.readFile); return readFile(services.config.apiNode.networkPropertyFilePath, 'utf8') .then(fileData => ini.parse(fileData)); }; - server.get('/network/currency/supply/circulating', (req, res, next) => readAndParseNetworkPropertiesFile() - .then(async propertiesObject => { - /* eslint-disable global-require */ - const accountIds = routeUtils.parseArgumentAsArray({ addresses: uncirculatedAddresses }, 'addresses', 'address'); - const currencyId = propertiesObject.chain.currencyMosaicId.replace(/'/g, '').replace('0x', ''); - const mosaicId = routeUtils.parseArgument({ mosaicId: currencyId }, 'mosaicId', 'uint64hex'); + const getUncirculatingAccountIds = propertiesObject => { + const publicKeys = [propertiesObject.network.nemesisSignerPublicKey].concat(services.config.uncirculatingAccountPublicKeys); + return publicKeys.map(publicKey => ({ [AccountType.publicKey]: convert.hexToUint8(publicKey) })); + }; - const mosaics = await db.mosaicsByIds([mosaicId]); - const accounts = await db.catapultDb.accountsByIds(accountIds.map(accountId => ({ [AccountType.address]: accountId }))); + const lookupMosaicAmount = (mosaics, currencyMosaicId) => { + const matchingMosaic = mosaics.find(mosaic => { + const mosaicId = longToUint64(mosaic.id); // convert Long to uint64 + return 0 === uint64.compare(currencyMosaicId, mosaicId); + }); - const totalSupply = parseInt(mosaics[0].mosaic.supply.toString(), 10); - const totalUncirculated = accounts.reduce((a, b) => a + parseInt(b.account.mosaics[0].amount.toString(), 10), 0); + return undefined === matchingMosaic ? 0 : matchingMosaic.amount.toNumber(); + }; - const circulatingSupply = (totalSupply - totalUncirculated).toString(); + server.get('/network/currency/supply/circulating', (req, res, next) => readAndParseNetworkPropertiesFile() + .then(async propertiesObject => { + const currencyMosaicId = propertyValueToMosaicId(propertiesObject.chain.currencyMosaicId); + const mosaics = await db.mosaicsByIds([currencyMosaicId]); + const accounts = await db.catapultDb.accountsByIds(getUncirculatingAccountIds(propertiesObject)); - sender.sendPlainText(res, next)(cmcUtils.convertToRelative(circulatingSupply)); - }).catch(() => { - res.send(errors.createInvalidArgumentError('there was an error reading the network properties file')); - next(); + const totalSupply = mosaics[0].mosaic.supply.toNumber(); + const burnedSupply = accounts.reduce( + (sum, account) => sum + lookupMosaicAmount(account.account.mosaics, currencyMosaicId), + 0 + ); + sender.sendPlainText(res, next)(cmcUtils.convertToRelative(totalSupply - burnedSupply)); })); server.get('/network/currency/supply/total', (req, res, next) => readAndParseNetworkPropertiesFile() .then(propertiesObject => { - const currencyId = propertiesObject.chain.currencyMosaicId.replace(/'/g, '').replace('0x', ''); - const mosaicId = routeUtils.parseArgument({ mosaicId: currencyId }, 'mosaicId', 'uint64hex'); - return db.mosaicsByIds([mosaicId]).then(response => { - const supply = response[0].mosaic.supply.toString(); - + const currencyMosaicId = propertyValueToMosaicId(propertiesObject.chain.currencyMosaicId); + return db.mosaicsByIds([currencyMosaicId]).then(response => { + const supply = response[0].mosaic.supply.toNumber(); sender.sendPlainText(res, next)(cmcUtils.convertToRelative(supply)); - }).catch(() => { - res.send(errors.createInvalidArgumentError('there was an error reading the network properties file')); - next(); }); })); server.get('/network/currency/supply/max', (req, res, next) => readAndParseNetworkPropertiesFile() .then(propertiesObject => { - const supply = propertiesObject.chain.maxMosaicAtomicUnits.replace(/'/g, '').replace('0x', ''); + const supply = parseInt(propertiesObject.chain.maxMosaicAtomicUnits.replace(/'/g, ''), 10); sender.sendPlainText(res, next)(cmcUtils.convertToRelative(supply)); - }).catch(() => { - res.send(errors.createInvalidArgumentError('there was an error reading the network properties file')); - next(); })); } }; diff --git a/rest/src/plugins/cmc/unCirculatedAccounts.js b/rest/src/plugins/cmc/unCirculatedAccounts.js deleted file mode 100644 index ba43e5ec..00000000 --- a/rest/src/plugins/cmc/unCirculatedAccounts.js +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2016-2019, Jaguar0625, gimre, BloodyRookie, Tech Bureau, Corp. - * Copyright (c) 2020-present, Jaguar0625, gimre, BloodyRookie. - * All rights reserved. - * - * This file is part of Catapult. - * - * Catapult is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Catapult is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Catapult. If not, see . - */ - -module.exports = [ - 'NCTOGU4INIO7DXLGWXBXBQHE3T6C6WBQNFUKY6A', // unclaimed cold - 'NB6BURBVCY4LEUA6J6NETHQW6O2O2QVKLKFK5MY', // unclaimed hot - 'NACXOOKIDID7S75S4FFSC7KBBIBHOBUXB5VSE7A', 'NALOQMBU45WOLZ4BCBYZX3N2Y2VSYQFOXGAO34A', 'NBNCW3DUUHGBCVJ53LYSYYNMKJ52TLR33C5U53A', - 'NB5NIEQF7FM7LLSFASHOQF4X3F6IPDYSIGR3UVA', 'NCAXT7RH6SUPXEU75EIPAPF7DM4VWUBC5AW2L4Q', 'NCE3EP762222D5D2UAF6KIFL7XZ7U4TPFWBYVHA', - 'NCKAC225JEFJTB3EO64MIVYF5D7YGZM2ZFXRJNI', 'NCQADXOA7ZHLUW2567H33HNNEKCOCN2OJ53PXIQ', 'NCTTMDTZUUQVN4OKTSF3FTEHJQL2QOGAV25MDCA', - 'NCVQPB2LZ6UCYKGYJAMCC7V4JGXA35BBY44BMHY', 'NCXX3KEIEZ3NABMUU45GM7X7BLMPMQHFOZMMF4Q', 'NDC3U2UERNMRYFQA45XC74TEEETTZPRUVWKFPAY', - 'NDF4ZCXFKIU5DSJEVBOOI2BDZMDKJTGJVBD6JRY', 'NDLFVQ3C25P5VO2VWP6AMHPIJT6FZYTXNJD4ZAY', 'NDLORKVADZSXTIVAA2FYLDMM7I32AIWE7HDWGUQ', - 'NDNGH7WJHSMULMCKYE333V6WU4CQDWXZIJK2VCY', 'NDRLHNV4W7W2M527QOIP35OI3HOMAGTCJDPFDEQ', 'NDSQX6J2QALD2XTU5NQ4FWA2MMEFKBOBEB2BIOQ', - 'NDX4GP6OL32EOSGXSB5FTGKXDJZP4D535ZZYDFI', 'ND6667LJBJJ6UMJSZKN2BLHQCS3WNZ3W4UGCFKI', 'NAQ3WTILPJUEKOOPNPOLJ7IG2TJSG4VKJ6SWBWA', - 'NBSEOUUMRL4QFZN3OBVXCD5LHMUOWEFDUC4GVUA', 'NBX2AMNDYWKPD76MSIIRKWPSGOTNNFFJOWMN64I', 'NCFNZEG73E7GUHZYYUJ2LQEA46JFS3F2XIMAW3A', - 'NCMYFGTYTPXVOEWRYKE56U3ZRUVBSP4ZZ7UAIIA', 'NCQ4WVGFRF34UYFGGJQ4UJLGAUQTP4T5NEQKGMQ', 'NC2545W433QN64625A26SA6VNFDD43YY5PGCDRA', - 'NC4GM67MOMEQYUZMOLB2H4Y74ESYCD2LPK5IQXI', 'NC5LLAV5MPYSMX6HVJ7ISY2S7OIGY3FSEIYGJAY', 'NDNCVE4SF3I62M3WLS65CZ7NA2NMDXJYZQCTXGQ', - 'NDRARXH6JHYTD5WJCZR3FMQW5ZLMQEGUR3JZSFA', 'NDYCPCRT2QXRFZYK4B2GRC4ISIXC4NXVWTZ5Z3A', 'NCPUTO6OUVSRSNDEOAJ5VNSMWDELRTND5VG2HDA', - 'NAPOVZAZGMT6LVG7TKR5FE7IC4T7VCMQJUMDUAA', 'NBNTWN3JJSAREDXYWARBYBPOXOWUO6H3GXL4EPY', 'NBMDALVKGYK562LXSESZT6FFNI65FDXFY5VOXSQ', - 'NABH3A5VDLYAVA73OV246JTVMAIPD2WEMAQL27I', 'NAL4XHZU6MANNNFQI4Z2WNMU3KRI2YW2MRRMHLI', 'NBBBCIKJV45U7PNYTNXETH2UFZLJ3C6TJKLJDQQ', - 'NBGEJ36QK43DR4MYB6XFUFLSVFLULX3HBVNRCVY', 'NBNRFJSGE53UNHBGZIHYZXPG7SHLQISJN5REGIY', 'NBRENIWJUCSUU7RJ5S2DEJVXAOJOTZZDKEFOC3I', - 'NBUW4OTD42VHELNPCLPQCUHNBHR47PQKLP2EKXA', 'NB5ORUTTH2QYHEVTDBB5WPQI4US22FNMODFRK5Y', 'NCASTBFHXMHGQB2UJVUDSW7ZI4N2FDW54OTSHKQ', - 'NCBLL63WUAL7FBNPZQISGJR4WZNB7RVWCWG25MI', 'NCC3VKV3V2HCAP2KTXJUWSXCJ3B6U32EKR6VU5I', 'NCFH35TMUJ5QJL6LTBYRBO7ERMM4NIBH7TL6TFY', - 'NCGCVCURBA2GCKPEGEA2Q6HKFEHYITKUNWRLMEA', 'NCNRS6KDPHV4MNMXOEGYD6LNRBMWUR7NT4SZI7I', 'NC2GXL6FQXZY3FXZAYJLBDQHBKSANZLGP4PL7VA', - 'NC5CFRDWEZVCMGQ4Y77OEFSQLMQ3V4EL7JERY2A', 'NC54KVIISZCMMB3ABAMV6NQ6DAUIYYVKQ23S73Q', 'NC7QENF6OO2FRYV7Q4B5Q74LRSC54Y3YNYN5O3Y', - 'NDE57ICE4UOAPUV3E4CYU3PBA2X4ABUGRGKDFBA', 'NDG6ORUW4PVWVQJRQ5AXADQBUQVL3KBX7AW7MUY', 'NDMR4GMUWGMODWY4FF2VZ3CEC2F56HTD3T6EJYY', - 'NDTNPG2NUA3MPVDXHLC6D5PSKM4JLLTMQJ5HEDY', 'ND2MRMODKMLCFJWPFJ4MDFI76R7FLZVKIIVKD3A', 'ND4MLYCECHPACYSDDQUFMPXONSIQLPAWNVBWSIA', - 'ND726EB3B2VG77J3EEQSGNGUX3SS6L2IEBS7PIY', 'NAAZKYH4V6SARDIJRGFXYEZIHVRWY7R2T62QFYA', 'NAGCLXJZHZSBM5ILN4LQBDKU4NYVHB6ZLGRTKJI', - 'NAIPUZBSDXZIHQKKILAFT3F43IQPS4LOZCH2H4Q', 'NA2KVKEQDZZMM3NGXYVBHZ46JHM46UWIX3KJ4AY', 'NA5ZUGHBUUHO63E5OQQND7CYK7UZ3HVQONR2O6Y', - 'NA7YZPY222RVYQMUM65ZSVFSPAHL55UWO3S35FY', 'NBGGUKW3GEUFHKTO4DYSGDTHIVPKAME3T2XSCGY', 'NBI2NEBVAD45WWV44H3A53AQ5675Z4G3ZDGDYLI', - 'NBQS3VKGOJ3YNIABN4Y4SFUDBDQHARUIVS6IMGQ', 'NB3WMVRI4RM3O3NUSWBZM7U4EZMKADSOFDPPJRQ', 'NCFFJV3VTAK6BJZNV6ZRUZKUJPOWST6MYFAAK5A', - 'NCRLDB2O2QDPU57PEG3D3AIFSGPGCZU7VVTKBUY', 'NCVG74MGUGR3PLVBWVNNACD6R37JA4RCQMXY3DY', 'NCVR72OUOHVGTVLYBKI7PLUDTIAYPRUWPMJJP3Q', - 'NDBKLXZWYBMUUTNRRZ5ESRAJYMQIMHGLGAYLTGY', 'NDQLBLKXVOK2YS5G7J3AYYKTNW3S3RRK6RQONAQ', 'ND6ZNSQG3I7VWLWSJ3DTYVPEZSJRGSEERW2F7DI', - 'NAE2BC5IQ6HAVL3SOJ3ENWMLNZVWJSSN4C4GMJQ', 'NAUXIAVKDQ7MYGY7EDNXYKMRFV6QUM5RJQVRTWI', 'NBQ2XKSB7HBT5SM5O36RYM57RLITSOLRC62HAOY', - 'NCFO4UXV5TWFO6UOIBUYZCB4ZB2KEVXJZMCIAHA', 'NCF7G3YVN5SHQQ7PUO5VUZLKHFBRQPOSJNNBUAQ', 'NCN26TKNQQXZIJ6JPQVHPWE4RR6IJTQCRJZKFIY', - 'NCOLND36Q2QY3VY2JBY5V565ROHFOWGWORRH2EA', 'NCXYYHL4TVBA3FAXHGUFX7GTFTROA4W5IFVC3NI', 'NDLEMSNJK524QEXKY4ZQLM5G2ON2557SSR775XA', - 'NAD3FRYYDCOQX66WE22L7IU2WJV4CP4EWSTP2GQ', 'NAGF2Z6SNW5LVTFZ4SYZFZACNOVS3E7YIAISMNA', 'NASUT5TVKVP2RM7W76CDS3QJZZN524LFOCII36I', - 'NBFU2WPO3GSR65NUINGYMPLH2246MWP2HCMY2GI', 'NBMBRKE3SWCDX42DAHQ4HEP3LXCHNYYMR6AXAGI', 'NBPRSZ6JI7WPBDYKX6OU6OJD5JLOMPQIQAXTPMQ', - 'NB3CEDY5PU534FQLL7VIQI5MQXLHUIWMZFIJEMY', 'NB4GHQQDRETKMTRXR6P2Y4CSHDULAQMPS6CGRFY', 'NB7NGG255EODTQVGYIN7VTWN5E6NCJX6M7KJAWI', - 'NCF63BYUDLEU22AVEQAAG4CNDCOQD6UFJZJMGFY', 'NCK4EQHDH5JOPLZ4IEOOGAN56M3MHMTAAHBVC2A', 'NCNHTLZ2445VPT3KOLK4APE7PIW73I7RPBPI6XQ', - 'NCPSXIPESZYYLOMDB3JKP4KQSE2BKGSYBOCBU3Q', 'NCQIDQQGK4IYXST6TSIFUIBRPNJVDDGQUHGR3TI', 'NCXYZW7YPCIHTQSBCJAEMH4KKP7X74JN56EOKNQ', - 'NCX6PYUTNYXK5R3HUVOO2UEFTDLCK7CE4YVB4XQ', 'NDCLSXHO4RSNUKK4EDLBWYZX5WBQOQBPTVLMSMQ', 'NDKSU3CKWVWNL4WDL5PMQ46MY5ND7RMK5GB4LKI', - 'NDVVKJBP2DISI5WGPN4HBSZ5B5GXOL3ERODFHPA', 'ND5YALPCYLD3I6JV4KMHTU4ORSDQ3CPGGOPSWJI', 'NA2DF2PKUACZTB5KTTZABMAIR43LNQYOE7FOVLY', - 'NAKFJTGMIAHMZXNB6M6WVRHFKAQWYEXYWTSTGBI', 'NBCNY4PULYTLMWVYYJWRDFTFODPHE3TBOUO2GNY', 'NDBJX22SLOP5DRAXZHZFCTZ3JAOMJQ6737FG75Y', - 'NDZRWMC74JGW23OB4W7SHVAAQ77UEE3JZ37QGYI', 'ND4E7JUQX73TGCXZGWMG6WDR27AVJ74QDW3EOUI', 'NAYF7RRNNL6652SSVGPMCCMPL7FMPJ2EO6FAH5Y', - 'NBFOERC6P2YY74O5HYQPZHNWBIL7YTHPZSGETSA', 'NCARLDVBLDKOMBVC22IPRTVZX72IYZCARRWR4FQ', 'NCNVQAWCEJL3TPOCVAVXF3RGMVMTI2HTUD47RTY', - 'ND2LYJD467WB7YSK6NFQTL2SFIPWFNTRW7K46EA' -]; diff --git a/rest/test/plugins/cmc/cmcRoutes_spec.js b/rest/test/plugins/cmc/cmcRoutes_spec.js index 89105f1e..dddd30f9 100644 --- a/rest/test/plugins/cmc/cmcRoutes_spec.js +++ b/rest/test/plugins/cmc/cmcRoutes_spec.js @@ -19,6 +19,7 @@ * along with Catapult. If not, see . */ +const { convertToLong } = require('../../../src/db/dbUtils'); const cmcRoutes = require('../../../src/plugins/cmc/cmcRoutes'); const cmcUtils = require('../../../src/plugins/cmc/cmcUtils'); const { MockServer } = require('../../routes/utils/routeTestUtils'); @@ -27,18 +28,22 @@ const { expect } = require('chai'); const sinon = require('sinon'); const fs = require('fs'); -const { uint64 } = catapult.utils; - describe('cmc routes', () => { describe('network currency supply', () => { const maxSupply = 9000000000000000; - const XYMSupply = 8998999998000000; + const xymSupply = 8998999998000000; + + const currencyMosaicId = '0x1234\'5678\'ABCD\'EF01'; + const nemesisSignerPublicKey = 'AF1B9DCF4FAD2CDC2C04B4F9CBDF3C9C884A9F05B40A59E233681E282DC824D9'; + const uncirculatingAccountPublicKey1 = 'D4912C4CA33F608E95B9C3ABAE59263B99E2DF6E87252D61F8DEFADF7DFFC455'; + const uncirculatingAccountPublicKey2 = '3BF1E1F3072E3BE0CD851E4741E101E33DB19C163895F69AA890E7CF177C878C'; + const circulatingAccountPublicKey1 = '346AA758B2ED98923204D7361A5A47C7B569C594C7904461C67459703D7B5874'; const mosaicsSample = [{ id: '', mosaic: { - id: '1234567890ABCDEF', - supply: XYMSupply, + id: convertToLong([0xABCDEF01, 0x12345678]), + supply: convertToLong(xymSupply), startHeight: '', ownerAddress: '', revision: 1, @@ -48,25 +53,34 @@ describe('cmc routes', () => { } }]; - const accountsSample = [{ - id: 'random1', - account: { - address: '', - addressHeight: '', - publicKey: '', - publicKeyHeight: '', - supplementalPublicKeys: {}, - importance: '', - importanceHeight: '', - activityBuckets: [], - mosaics: [ - { id: 0, amount: uint64.fromUint((1000000)) } - ] - } - }]; + const createAccountSample = (publicKey, currencyAmount, otherAmount) => ({ + address: '', + addressHeight: '', + publicKey: catapult.utils.convert.hexToUint8(publicKey), + publicKeyHeight: '', + supplementalPublicKeys: {}, + importance: '', + importanceHeight: '', + activityBuckets: [], + mosaics: [ + { id: convertToLong([0xABCDEF01, 0x22222222]), amount: convertToLong(otherAmount) }, + { id: convertToLong([0xABCDEF01, 0x12345678]), amount: convertToLong(currencyAmount) } + ] + }); + + const accountsSample = [ + { id: 'random1', account: createAccountSample(nemesisSignerPublicKey, 1000000, 9000000) }, + { id: 'random2', account: createAccountSample(uncirculatingAccountPublicKey1, 2000000, 9000000) }, + { id: 'random3', account: createAccountSample(circulatingAccountPublicKey1, 4000000, 9000000) }, + { id: 'random4', account: createAccountSample(uncirculatingAccountPublicKey2, 8000000, 9000000) } + ]; const dbMosaicsFake = sinon.fake(() => Promise.resolve(mosaicsSample)); - const dbAccountsFake = sinon.fake(() => Promise.resolve(accountsSample)); + const dbAccountsFake = sinon.fake(accountIds => { + const filteredAccountsSample = accountsSample.filter(accountSample => + accountIds.some(accountId => catapult.utils.array.deepEqual(accountId.publicKey, accountSample.account.publicKey))); + return Promise.resolve(filteredAccountsSample); + }); const mockServer = new MockServer(); @@ -77,69 +91,90 @@ describe('cmc routes', () => { } }; - const services = { config: { apiNode: {} } }; + const services = { + config: { + apiNode: {}, + uncirculatingAccountPublicKeys: [uncirculatingAccountPublicKey1, uncirculatingAccountPublicKey2] + } + }; cmcRoutes.register(mockServer.server, db, services); const req = { params: {} }; - beforeEach(() => { + afterEach(() => { mockServer.resetStats(); dbMosaicsFake.resetHistory(); + fs.readFile.restore(); }); describe('GET', () => { - it('network currency supply circulating', () => { - const readFileStub = sinon.stub(fs, 'readFile').callsFake((path, data, callback) => - callback(null, `[chain]\nmaxMosaicAtomicUnits = ${maxSupply}\ncurrencyMosaicId = "0x1234567890ABCDEF"`)); - + it('network currency supply circulating (without burns)', () => { + sinon.stub(fs, 'readFile').callsFake((path, data, callback) => + callback(null, [ + '[network]', + `nemesisSignerPublicKey=${nemesisSignerPublicKey}`, + '', + '[chain]', + 'currencyMosaicId = 0x1234\'5678\'ABCD\'EF02' + ].join('\n'))); const route = mockServer.getRoute('/network/currency/supply/circulating').get(); - // Arrange: - const totalUncirculated = accountsSample.reduce((a, b) => a + parseInt(b.account.mosaics[0].amount.toString(), 10), 0); - const circulatingSupply = XYMSupply - totalUncirculated; + // Act: + return mockServer.callRoute(route, req).then(() => { + // Assert: + expect(mockServer.next.calledOnce).to.equal(true); + + const expectedSupply = mosaicsSample[0].mosaic.supply - 0; + expect(mockServer.send.firstCall.args[0]).to.equal(cmcUtils.convertToRelative(expectedSupply)); + }); + }); + + it('network currency supply circulating (with burns)', () => { + sinon.stub(fs, 'readFile').callsFake((path, data, callback) => + callback(null, [ + '[network]', + `nemesisSignerPublicKey=${nemesisSignerPublicKey}`, + '', + '[chain]', + `currencyMosaicId = ${currencyMosaicId}` + ].join('\n'))); + const route = mockServer.getRoute('/network/currency/supply/circulating').get(); // Act: return mockServer.callRoute(route, req).then(() => { - // Assert + // Assert: expect(mockServer.next.calledOnce).to.equal(true); - expect(mockServer.send.firstCall.args[0]).to.equal(cmcUtils.convertToRelative(circulatingSupply)); - readFileStub.restore(); + + const expectedSupply = mosaicsSample[0].mosaic.supply - 11000000; + expect(mockServer.send.firstCall.args[0]).to.equal(cmcUtils.convertToRelative(expectedSupply)); }); }); it('network currency supply total', () => { - const readFileStub = sinon.stub(fs, 'readFile').callsFake((path, data, callback) => - callback(null, '[chain]\ncurrencyMosaicId = 0x1234567890ABCDEF')); + sinon.stub(fs, 'readFile').callsFake((path, data, callback) => + callback(null, `[chain]\ncurrencyMosaicId = ${currencyMosaicId}`)); const route = mockServer.getRoute('/network/currency/supply/total').get(); - // Arrange: - const xymSupply = cmcUtils.convertToRelative(mosaicsSample[0].mosaic.supply); - // Act: return mockServer.callRoute(route, req).then(() => { - // Assert + // Assert: expect(mockServer.next.calledOnce).to.equal(true); - expect(mockServer.send.firstCall.args[0]).to.equal(xymSupply); - readFileStub.restore(); + expect(mockServer.send.firstCall.args[0]).to.equal(cmcUtils.convertToRelative(mosaicsSample[0].mosaic.supply)); }); }); it('network currency supply max', () => { - const readFileStub = sinon.stub(fs, 'readFile').callsFake((path, data, callback) => + sinon.stub(fs, 'readFile').callsFake((path, data, callback) => callback(null, `[chain]\nmaxMosaicAtomicUnits = ${maxSupply}`)); const route = mockServer.getRoute('/network/currency/supply/max').get(); - // Arrange: - const mosaicMaxSupply = cmcUtils.convertToRelative(maxSupply); - // Act: return mockServer.callRoute(route, req).then(() => { - // Assert + // Assert: expect(mockServer.next.calledOnce).to.equal(true); - expect(mockServer.send.firstCall.args[0]).to.equal(mosaicMaxSupply); - readFileStub.restore(); + expect(mockServer.send.firstCall.args[0]).to.equal(cmcUtils.convertToRelative(maxSupply)); }); }); });