diff --git a/dist/api/Address.js b/dist/api/Address.js index e3020cc2..8e2a3016 100644 --- a/dist/api/Address.js +++ b/dist/api/Address.js @@ -1,8 +1,7 @@ 'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.Address = undefined;var _DataCollector = require('../lib/DataCollector'); var _types = require('../lib/types'); var _config = require('../lib/config');var _config2 = _interopRequireDefault(_config);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} -const bridgeAddress = _config2.default.bridgeAddress; -const remascAddress = _config2.default.remascAddress; +const { bridgeAddress, remascAddress } = _config2.default; class Address extends _DataCollector.DataCollectorItem { constructor(collection, key, parent) { let sortable = { 'createdByTx.timestamp': -1 }; diff --git a/dist/api/Blocks.js b/dist/api/Blocks.js index df558c8c..8f8802f2 100644 --- a/dist/api/Blocks.js +++ b/dist/api/Blocks.js @@ -71,9 +71,12 @@ class Blocks extends _DataCollector.DataCollector { this.events.emit('newBlocks', this.formatData({ blocks, transactions })); } } + async getAddress(address) { + return this.Address.run('getAddress', { address }); + } async addAddressData(address, data, key = '_addressData') { - const account = await this.Address.run('getAddress', { address }); + const account = await this.getAddress(address); if (data && data.data && account) data.data[key] = account.data; return data || account; }}exports.default = diff --git a/dist/api/Event.js b/dist/api/Event.js index 73b55031..0befcfe7 100644 --- a/dist/api/Event.js +++ b/dist/api/Event.js @@ -1,13 +1,15 @@ 'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.Event = undefined;var _DataCollector = require('../lib/DataCollector'); +var _config = require('../lib/config');var _config2 = _interopRequireDefault(_config);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} +const { remascAddress, bridgeAddress } = _config2.default; class Event extends _DataCollector.DataCollectorItem { constructor(collection, key, parent) { - const sortable = { timestamp: -1 }; - super(collection, key, parent, { sortable }); + // const sortable = { timestamp: -1 } + super(collection, key, parent); this.publicActions = { getEvent: async params => { try { - const _id = params._id; + const { _id } = params; let data = await this.getOne({ _id }); if (!data) throw new Error(`Event ${_id} does not exist`); const address = data.data.address; @@ -19,8 +21,42 @@ class Event extends _DataCollector.DataCollectorItem { }, getEventsByAddress: async params => { - const address = params.address; - if (address) return this.getPageData({ address }, params); + const { address, signatures, contract } = params; + if (address) { + let query = { args: address + + // search by events signatures + };if (Array.isArray(signatures)) { + // skip remasc & bridge events + if (address !== remascAddress && address !== bridgeAddress) { + query.signature = { $in: signatures }; + } + } + + if (contract) query.address = contract; + + let res = await this.getPageData(query, params); + if (res.data) { + let addresses = new Set(res.data.map(d => d.address)); + addresses = [...addresses.values()]; + let addrData = await this.parent.Address.find({ address: { $in: addresses } }); + let { data } = addrData; + if (data) { + res.data = res.data.map(d => { + d._addressData = data.find(a => a.address === d.address); + return d; + }); + } + } + return res; + } + }, + + getAllEventsByAddress: async params => { + const { address } = params; + if (address) { + return this.getPageData({ $or: [{ address }, { args: address }] }, params); + } } }; }}exports.Event = Event;exports.default = diff --git a/dist/api/TokenAccount.js b/dist/api/TokenAccount.js index 172094cc..69ed582e 100644 --- a/dist/api/TokenAccount.js +++ b/dist/api/TokenAccount.js @@ -1,4 +1,6 @@ 'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.TokenAccount = undefined;var _DataCollector = require('../lib/DataCollector'); +var _utils = require('../lib/utils'); +var _bignumber = require('bignumber.js'); class TokenAccount extends _DataCollector.DataCollectorItem { constructor(collection, key, parent) { @@ -36,6 +38,25 @@ class TokenAccount extends _DataCollector.DataCollectorItem { const { address, contract } = params; const account = await this.getOne({ address, contract }); return this.parent.addAddressData(contract, account, '_contractData'); + }, + + getTokenBalance: async params => { + const { contract } = params; + let contractData = await this.parent.getAddress(contract); + contractData = contractData.data; + if (!contractData) return; + let { totalSupply } = contractData; + if (!totalSupply) return; + let accounts = await this.find({ contract }); + if (accounts) accounts = accounts.data; + if (!accounts) return; + + let accountsBalance = (0, _utils.bigNumberSum)(accounts.map(account => account.balance)); + totalSupply = new _bignumber.BigNumber(totalSupply); + let balance = accountsBalance ? totalSupply.minus(accountsBalance) : totalSupply; + + const data = this.serialize({ balance, accountsBalance, totalSupply }); + return { data }; } }; }}exports.TokenAccount = TokenAccount;exports.default = diff --git a/dist/lib/ContractParser/ContractParser.js b/dist/lib/ContractParser/ContractParser.js index 4466c173..e16a59db 100644 --- a/dist/lib/ContractParser/ContractParser.js +++ b/dist/lib/ContractParser/ContractParser.js @@ -4,7 +4,8 @@ var _web3Connect = require('../web3Connect'); var _types = require('../types'); var _interfacesIds = require('./interfacesIds');var _interfacesIds2 = _interopRequireDefault(_interfacesIds); var _utils = require('../../lib/utils'); - +var _config = require('../config');var _config2 = _interopRequireDefault(_config); +var _RemascEvents = require('./RemascEvents');var _RemascEvents2 = _interopRequireDefault(_RemascEvents); var _lib = require('./lib');function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} @@ -14,6 +15,8 @@ var _lib = require('./lib');function _interopRequireDefault(obj) {return obj && + +const { remascAddress } = _config2.default; class ContractParser { constructor(abi, options = {}) { this.abi = null; @@ -55,6 +58,9 @@ class ContractParser { parseTxLogs(logs) { return logs.map(log => { + // non-standard remasc events + if (log.address === remascAddress) return _RemascEvents2.default.decode(log); + let back = Object.assign({}, log); let decoder = this.getLogDecoder(log.topics || []); let decoded = decoder ? decoder.event.decode(log) : log; @@ -152,7 +158,7 @@ class ContractParser { let methods = this.getMethodsBySelectors(txInputData); let isErc165 = false; // skip non-erc165 conrtacts - if ((0, _utils.hasValues)(methods, ['supportsInterface(bytes4)'])) { + if ((0, _utils.includesAll)(methods, ['supportsInterface(bytes4)'])) { isErc165 = await this.implementsErc165(contract); } let interfaces; @@ -176,7 +182,7 @@ class ContractParser { getInterfacesByMethods(methods, isErc165) { return Object.keys(_interfacesIds2.default). map(i => { - return [i, (0, _utils.hasValues)(methods, _interfacesIds2.default[i].methods)]; + return [i, (0, _utils.includesAll)(methods, _interfacesIds2.default[i].methods)]; }). reduce((obj, value) => { obj[value[0]] = value[1]; diff --git a/dist/lib/ContractParser/RemascEvents.js b/dist/lib/ContractParser/RemascEvents.js new file mode 100644 index 00000000..2c75dd23 --- /dev/null +++ b/dist/lib/ContractParser/RemascEvents.js @@ -0,0 +1,56 @@ +'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.RemascEvents = undefined;var _rlp = require('rlp');var rlp = _interopRequireWildcard(_rlp);function _interopRequireWildcard(obj) {if (obj && obj.__esModule) {return obj;} else {var newObj = {};if (obj != null) {for (var key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key];}}newObj.default = obj;return newObj;}} + +class RemascEvents { + decode(log) { + let event = this.decodeEventName(log.topics[0]); + // at the moment remasc emits only one event + if (event === 'mining_fee_topic') { + let [blockHash, value] = this.decodeData(log.data); + let to = this.decodeAddress(log.topics[1]); + log.event = event; + log.args = [to, blockHash, value]; + log.abi = this.fakeAbi(); + } + return log; + } + + decodeEventName(name) { + name = name.slice(0, 2) === '0x' ? name.slice(2, name.length) : name; + return Buffer.from(name, 'hex').toString('ascii').replace(/\0/g, ''); + } + + decodeData(data) { + return rlp.decode(data).map(d => '0x' + d.toString('hex').replace(/^0+/, '')); + } + + decodeAddress(address) { + return '0x' + address.slice(-40); + } + fakeAbi() { + return { + anonymous: false, + inputs: [ + { + indexed: true, + name: 'to', + type: 'address' }, + + { + indexed: false, + name: 'blockHash', + type: 'address' }, + + { + indexed: false, + name: 'value', + type: 'uint256' }], + + + name: 'mining_fee_topic', + type: 'event' }; + + }}exports.RemascEvents = RemascEvents; + + +const remascEvents = new RemascEvents();exports.default = +remascEvents; \ No newline at end of file diff --git a/dist/lib/collections.js b/dist/lib/collections.js index b4450c48..52cc34aa 100644 --- a/dist/lib/collections.js +++ b/dist/lib/collections.js @@ -105,7 +105,15 @@ { key: { blockNumber: 1 }, - name: 'eventBlockNumberIndex' }], + name: 'eventBlockNumberIndex' }, + + { + key: { args: 1 }, + name: 'eventsArgsIndex' }, + + { + key: { signature: 1 }, + name: 'eventSignatureIndex' }], TokensAddrs: [ diff --git a/dist/lib/utils.js b/dist/lib/utils.js index 97b4f523..4d03b151 100644 --- a/dist/lib/utils.js +++ b/dist/lib/utils.js @@ -1,4 +1,4 @@ -'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.jsonDecode = exports.jsonEncode = exports.keccak256 = exports.base64toHex = exports.btoa = exports.atob = exports.hasValues = exports.hasValue = exports.arraySymmetricDifference = exports.arrayDifference = exports.arrayIntersection = exports.getBestBlock = exports.blockQuery = exports.isBlockHash = exports.checkBlockHash = exports.serialize = exports.bigNumberToSring = exports.unSerializeBigNumber = exports.isSerializedBigNumber = exports.serializeBigNumber = exports.isBigNumber = exports.bigNumberDoc = exports.isValidAddress = exports.isAddress = exports.remove0x = exports.add0x = exports.isHexString = undefined;var _bignumber = require('bignumber.js'); +'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.jsonDecode = exports.jsonEncode = exports.keccak256 = exports.base64toHex = exports.btoa = exports.atob = exports.includesAll = exports.hasValue = exports.arraySymmetricDifference = exports.arrayDifference = exports.arrayIntersection = exports.getBestBlock = exports.blockQuery = exports.isBlockHash = exports.checkBlockHash = exports.serialize = exports.bigNumberSum = exports.bigNumberToSring = exports.unSerializeBigNumber = exports.isSerializedBigNumber = exports.serializeBigNumber = exports.isBigNumber = exports.bigNumberDoc = exports.isValidAddress = exports.isAddress = exports.remove0x = exports.add0x = exports.isHexString = undefined;var _bignumber = require('bignumber.js'); var _types = require('./types'); var _mongodb = require('mongodb'); var _keccak = require('keccak');var _keccak2 = _interopRequireDefault(_keccak);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };} @@ -8,9 +8,25 @@ const isHexString = exports.isHexString = str => { return (/^[0-9a-f]+$/i.test(str)); }; -const add0x = exports.add0x = str => isHexString(str) && str.substring(0, 2) !== '0x' ? `0x${str}` : str; +const add0x = exports.add0x = str => { + let s = str; + let prefix = s[0] === '-' ? '-' : ''; + if (prefix) s = s.substring(prefix.length); + if (isHexString(s) && s.substring(0, 2) !== '0x') { + return `${prefix}0x${s}`; + } + return str; +}; -const remove0x = exports.remove0x = str => isHexString(str) && str.substring(0, 2) === '0x' ? str.substr(2, str.length) : str; +const remove0x = exports.remove0x = str => { + let s = str; + let prefix = s[0] === '-' ? '-' : ''; + if (prefix) s = s.substring(prefix.length); + if (isHexString(s)) { + if (s.substring(0, 2) === '0x') return prefix + s.substr(2); + } + return str; +}; const isAddress = exports.isAddress = address => { return (/^(0x)?[0-9a-f]{40}$/i.test(address)); @@ -50,6 +66,16 @@ const bigNumberToSring = exports.bigNumberToSring = bn => { return bn; }; +const bigNumberSum = exports.bigNumberSum = values => { + let total = new _bignumber.BigNumber(0); + values. + forEach(value => { + value = isBigNumber(value) ? value : new _bignumber.BigNumber(value); + total = total.plus(value); + }); + return total; +}; + const isObj = value => { if (undefined === value || value === null) return false; let is = typeof value === 'object'; @@ -117,7 +143,7 @@ const arraySymmetricDifference = exports.arraySymmetricDifference = (a, b) => ar const hasValue = exports.hasValue = (arr, search) => arrayIntersection(arr, search).length > 0; -const hasValues = exports.hasValues = (arr, search) => !search.map(t => arr.indexOf(t)).filter(i => i < 0).length; +const includesAll = exports.includesAll = (arr, search) => !search.map(t => arr.indexOf(t)).filter(i => i < 0).length; const atob = exports.atob = str => Buffer.from(str, 'base64').toString('binary'); diff --git a/dist/services/classes/GetTxBalance.js b/dist/services/classes/GetTxBalance.js index b3dda0e8..70dc69b3 100644 --- a/dist/services/classes/GetTxBalance.js +++ b/dist/services/classes/GetTxBalance.js @@ -1,4 +1,4 @@ -'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.GetTxBalance = undefined;var _bignumber = require('bignumber.js'); +'use strict';Object.defineProperty(exports, "__esModule", { value: true });exports.GetTxBalance = undefined;var _utils = require('../../lib/utils'); class GetTxBalance { constructor(txCollection) { this.txCollection = txCollection; @@ -13,13 +13,7 @@ class GetTxBalance { } sumValues(values) { - let total = new _bignumber.BigNumber(0); - values. - map(v => v.value). - forEach(value => { - total = total.plus(new _bignumber.BigNumber(value)); - }); - return total; + return (0, _utils.bigNumberSum)(values.map(v => v.value)); } async getBalanceFromTx(address) { diff --git a/dist/tools/wsGet.js b/dist/tools/wsGet.js index da787535..cf07b381 100644 --- a/dist/tools/wsGet.js +++ b/dist/tools/wsGet.js @@ -7,7 +7,7 @@ const writeFile = _util2.default.promisify(_fs2.default.writeFile); const url = process.env.url || 'http://localhost:3003'; const outDir = process.env.outDir || '/tmp'; -let payload = process.env.payload; +let payload = process.env.payload || process.argv[2]; if (!url || !payload) help(); payload = JSON.parse(payload); @@ -35,8 +35,10 @@ socket.on('disconnect', socket => { socket.on('data', async res => { try { let { data, error, req } = res; - - if (error) throw new Error(error); + if (error) { + c.error(error); + process.exit(); + } if (!error && req && key === req.key) { // multiple results if (res.pages) { @@ -70,8 +72,9 @@ socket.on('data', async res => { }); socket.on('Error', err => { - c.error('ERROR:'); - c.error(err); + let error = err.error || ''; + c.error(`ERROR: ${error}`); + c.warn(err); }); process.on('unhandledRejection', err => { diff --git a/package-lock.json b/package-lock.json index 0b67367e..451fb60a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "rsk-explorer-api", - "version": "0.7.1", + "version": "0.7.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7932b361..b7d5d6d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rsk-explorer-api", - "version": "0.7.1", + "version": "0.7.2", "description": "", "main": "index.js", "scripts": {