Skip to content
This repository has been archived by the owner on Jun 10, 2022. It is now read-only.

Commit

Permalink
Task/607 refactor currency supply endpoints (#610)
Browse files Browse the repository at this point in the history
* create network currency plugin on catapult-sdk

* moved all function to plugin

* rename to cmc

* added cmc plugin for REST

* addded cmc utils

* added pluges test

* lint fixes

* update test case to pass travis
  • Loading branch information
AnthonyLaw authored May 17, 2021
1 parent e59bb2c commit 5f5d60b
Show file tree
Hide file tree
Showing 21 changed files with 625 additions and 80 deletions.
4 changes: 3 additions & 1 deletion catapult-sdk/src/plugins/catapultModelSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
/** @module plugins/catapultModelSystem */
const accountLink = require('./accountLink');
const aggregate = require('./aggregate');
const cmc = require('./cmc');
const lockHash = require('./lockHash');
const lockSecret = require('./lockSecret');
const metadata = require('./metadata');
Expand All @@ -46,7 +47,8 @@ const plugins = {
namespace,
receipts,
restrictions,
transfer
transfer,
cmc
};

/**
Expand Down
38 changes: 38 additions & 0 deletions catapult-sdk/src/plugins/cmc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/

/** @module plugins/cmc */

// To ensure cmc able to load from the config, created empty plugins

/* eslint-disable no-unused-vars */

/**
* Creates a cmc plugin use for CoinMarketCap.
* @type {module:plugins/CatapultPlugin}
*/
const cmcPlugin = {
registerSchema: builder => {},

registerCodecs: codecBuilder => {}
};

module.exports = cmcPlugin;
3 changes: 2 additions & 1 deletion catapult-sdk/test/plugins/catapultModelSystem_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ describe('catapult model system', () => {
'namespace',
'receipts',
'restrictions',
'transfer'
'transfer',
'cmc'
]);
});
});
Expand Down
51 changes: 51 additions & 0 deletions rest/src/plugins/cmc/CmcDb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/

const { convertToLong } = require('../../db/dbUtils');

class CmcDb {
/**
* Creates NetworkCurrencyDb around CatapultDb.
* @param {module:db/CatapultDb} db Catapult db instance.
*/
constructor(db) {
this.catapultDb = db;
}

// region NetworkCurrency retrieval
/**
* Retrieves mosaics given their ids.
* @param {Array.<module:catapult.utils/uint64~uint64>} ids Mosaic ids.
* @returns {Promise.<array>} Mosaics.
*/
mosaicsByIds(ids) {
const mosaicIds = ids.map(id => convertToLong(id));
const conditions = { 'mosaic.id': { $in: mosaicIds } };
const collection = this.catapultDb.database.collection('mosaics');
return collection.find(conditions)
.sort({ _id: -1 })
.toArray()
.then(entities => Promise.resolve(this.catapultDb.sanitizer.renameIds(entities)));
}
// endregion
}

module.exports = CmcDb;
40 changes: 40 additions & 0 deletions rest/src/plugins/cmc/cmc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/

/** @module plugins/cmc */
const CmcDb = require('./CmcDb');
const cmcRoutes = require('./cmcRoutes');

/**
* Creates a cmc plugin.
* @type {module:plugins/CatapultRestPlugin}
*/
module.exports = {
createDb: db => new CmcDb(db),

registerTransactionStates: () => {},

registerMessageChannels: () => {},

registerRoutes: (...args) => {
cmcRoutes.register(...args);
}
};
85 changes: 85 additions & 0 deletions rest/src/plugins/cmc/cmcRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/

const cmcUtils = require('./cmcUtils');
const uncirculatedAddresses = require('./unCirculatedAccounts');
const routeUtils = require('../../routes/routeUtils');
const errors = require('../../server/errors');
const AccountType = require('../AccountType');
const ini = require('ini');
const fs = require('fs');
const util = require('util');

module.exports = {
register: (server, db, services) => {
const sender = routeUtils.createSender('cmc');

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 mosaics = await db.mosaicsByIds([mosaicId]);
const accounts = await db.catapultDb.accountsByIds(accountIds.map(accountId => ({ [AccountType.address]: accountId })));

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);

const circulatingSupply = (totalSupply - totalUncirculated).toString();

sender.sendPlainText(res, next)(cmcUtils.convertToRelative(circulatingSupply));
}).catch(() => {
res.send(errors.createInvalidArgumentError('there was an error reading the network properties file'));
next();
}));

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();

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', '');
sender.sendPlainText(res, next)(cmcUtils.convertToRelative(supply));
}).catch(() => {
res.send(errors.createInvalidArgumentError('there was an error reading the network properties file'));
next();
}));
}
};
26 changes: 26 additions & 0 deletions rest/src/plugins/cmc/cmcUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/

const cmcUtils = {
convertToRelative: absolute => (Number(absolute) / (10 ** 6)).toFixed(6)
};

module.exports = cmcUtils;
23 changes: 0 additions & 23 deletions rest/src/plugins/mosaic/mosaicRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@
const merkleUtils = require('../../routes/merkleUtils');
const routeUtils = require('../../routes/routeUtils');
const catapult = require('catapult-sdk');
const ini = require('ini');
const fs = require('fs');
const util = require('util');

const { PacketType } = catapult.packet;

Expand Down Expand Up @@ -63,25 +60,5 @@ module.exports = {
next();
});
});

// CMC specific endpoint
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/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 s = response[0].mosaic.supply.toString();
const supply = `${s.substring(0, s.length - 6)}.${s.substring(s.length - 6, s.length)}`;
res.setHeader('content-type', 'text/plain');
res.send(supply);
next();
});
}));
}
};
4 changes: 3 additions & 1 deletion rest/src/plugins/routeSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/

const aggregate = require('./aggregate/aggregate');
const cmc = require('./cmc/cmc');
const empty = require('./empty');
const lockHash = require('./lockHash/lockHash');
const lockSecret = require('./lockSecret/lockSecret');
Expand All @@ -43,7 +44,8 @@ const plugins = {
namespace,
receipts,
restrictions,
transfer: empty
transfer: empty,
cmc
};

module.exports = {
Expand Down
34 changes: 0 additions & 34 deletions rest/src/routes/accountRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@ const merkleUtils = require('./merkleUtils');
const routeResultTypes = require('./routeResultTypes');
const routeUtils = require('./routeUtils');
const AccountType = require('../plugins/AccountType');
const MosaicDb = require('../plugins/mosaic/MosaicDb');
const errors = require('../server/errors');
const catapult = require('catapult-sdk');
const ini = require('ini');
const fs = require('fs');
const util = require('util');

const { PacketType } = catapult.packet;

Expand Down Expand Up @@ -84,35 +80,5 @@ module.exports = {
next();
});
});

// CMC specific endpoint
const readAndParseNetworkPropertiesFile = () => {
const readFile = util.promisify(fs.readFile);
return readFile(services.config.apiNode.networkPropertyFilePath, 'utf8')
.then(fileData => ini.parse(fileData));
};

// CMC specific endpoint
server.get('/network/currency/supply/circulating', (req, res, next) => readAndParseNetworkPropertiesFile()
.then(async propertiesObject => {
const mosaicDB = new MosaicDb(db);
/* eslint-disable global-require */
const uncirculatedAddresses = require('../constants/unCirculatedAccounts');
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 mosaics = await mosaicDB.mosaicsByIds([mosaicId]);
const accounts = await db.accountsByIds(accountIds.map(accountId => ({ [AccountType.address]: accountId })));

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);

const s = (totalSupply - totalUncirculated).toString();
const result = `${s.substring(0, s.length - 6)}.${s.substring(s.length - 6, s.length)}`;
res.setHeader('content-type', 'text/plain');
res.send(result);
next();
}));
}
};
12 changes: 0 additions & 12 deletions rest/src/routes/networkRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,5 @@ module.exports = {
next();
});
});

// CMC specific, only return the plain value of the max mosaic supply
server.get('/network/currency/supply/max', (req, res, next) => readAndParseNetworkPropertiesFile()
.then(propertiesObject => {
const maxSupply = propertiesObject.chain.maxMosaicAtomicUnits.replace(/'/g, '').slice(0, -6);
res.setHeader('content-type', 'text/plain');
res.send(maxSupply);
next();
}).catch(() => {
res.send(errors.createInvalidArgumentError('there was an error reading the network properties file'));
next();
}));
}
};
Loading

0 comments on commit 5f5d60b

Please sign in to comment.