UNPKG

sirius-explorer

Version:

An open-source front-end for the Insight API.

1,864 lines (1,422 loc) 121 kB
// Source: public/src/js/app.js angular.module('insight', [ 'ngResource', 'ngRoute', 'ngLodash', 'ui.bootstrap', 'ui.route', 'monospaced.qrcode', 'gettext', 'angularMoment', 'insight.system', 'insight.socket', 'insight.blocks', 'insight.chart', 'insight.charts', 'insight.richList', 'insight.transactions', 'insight.address', 'insight.search', 'insight.statistics', 'insight.status', 'insight.markets', 'insight.connection', 'insight.currency', 'insight.messages', 'insight.siriuscorelib', 'insight.bignumber', 'insight.solidity_coder', 'insight.web3_utils', 'insight.contracts', 'insight.opcodes', 'insight.networks', 'insight.token' ]); angular.module('insight.system', ['ngScrollbars', 'chart.js']); angular.module('insight.socket', []); angular.module('insight.blocks', []); angular.module('insight.charts', []); angular.module('insight.chart', []); angular.module('insight.richList', []); angular.module('insight.transactions', ['ngScrollbars', 'jQueryScrollbar']); angular.module('insight.address', []); angular.module('insight.search', []); angular.module('insight.token', ['ngNumeraljs']); angular.module('insight.statistics', ['ngNumeraljs']); angular.module('insight.status', []); angular.module('insight.markets', []); angular.module('insight.connection', []); angular.module('insight.currency', []); angular.module('insight.messages', []); angular.module('insight.messages', []); angular.module('insight.siriuscorelib', []); angular.module('insight.contracts', []); angular.module('insight.opcodes', []); angular.module('insight.networks', []); angular.module('insight.solidity_coder', []); angular.module('insight.web3_utils', []); angular.module('insight.bignumber', []); // Source: public/src/js/controllers/address.js angular.module('insight.address').controller('AddressController', function($scope, $rootScope, $document, $routeParams, $location, $window, Address, getSocket, Constants, ContractsInfo, Contracts, ERC20AddressBalances, ERC20ContractInfo, Web3Utils) { var self = this; var socket = getSocket($scope); var addrStr = $routeParams.addrStr; self.contractAddress = null; if (Web3Utils.isAddress(addrStr)) { self.contractAddress = addrStr; addrStr = Contracts.getBitAddressFromContractAddress(addrStr); } var hexString = '0000000000000000000000000000000000000000000000000000000000000000'; self.STORAGE_ROWS = Constants.STORAGE_ROWS; self.STORAGE_CONST = { STRING: 'string', NUMBER: 'number', ADDRESS: 'address', DATA: 'data' }; self.storageViews = [ self.STORAGE_CONST.DATA, self.STORAGE_CONST.STRING, self.STORAGE_CONST.NUMBER, self.STORAGE_CONST.ADDRESS ]; self.storage = {}; self.info = null; self.erc20ContractInfo = null; self.scrollConfig = { autoHideScrollbar: false, theme: 'custom', advanced:{ updateOnContentResize: true }, scrollInertia: 0 }; self.tooltipOptions = { animation: 'fade', theme: 'tooltipster-black', trigger: 'click', interactive: true }; self.qrColors = { background: Constants.QRCOLOR.background, color: Constants.QRCOLOR.color }; self.balances = []; var _startSocket = function() { socket.on('siriusd/addresstxid', function(data) { if (data.address === addrStr) { var base = $document.find('base'); var beep = new Audio(base[0].href + '/sound/transaction.mp3'); $rootScope.$broadcast('tx', data.txid); beep.play(); } }); socket.emit('subscribe', 'siriusd/addresstxid', [addrStr]); }; var _parseStorageRowType = function(hex, type) { switch (type){ case 'string': { var str = ""; var i = 0, l = hex.length; if (hex.substring(0, 2) === '0x') { i = 2; } for (; i < l; i+=2) { var code = parseInt(hex.substr(i, 2), 16); if (code === 0 && str) break; str += String.fromCharCode(code); } return str; } case 'number': { return parseInt(hex, 16); } case 'address': { return hex.substr(-40); } case 'data': { return hexString.substr(hex.length).concat(hex); } default: { return hex; } } }; var _defineDefaultState = function(string, number){ var stringMatchUnread = string.match(/[^a-zA-Z0-9;:'".,\/\]\[?!&%#@)(_`><\s]/g) || []; var stringMatchRead = string.match(/[a-zA-Z0-9;:'".,\/\]\[?!&%#@)(_`><]/g); var isLastSymbolUnread = string[ string.length - 1 ] === stringMatchUnread[0]; if(!~(number.toString().indexOf('e'))){ return self.STORAGE_CONST.NUMBER; } if((isLastSymbolUnread || !stringMatchUnread.length) && stringMatchRead){ return self.STORAGE_CONST.STRING; } return self.STORAGE_CONST.DATA; }; var _formStorageInfo = function() { var rows = []; for(var row in self.info.storage){ if(self.info.storage.hasOwnProperty(row)){ for(var key in self.info.storage[ row ]){ var newRow = { values: {}, keys: {} }; if(self.info.storage[ row ].hasOwnProperty(key)){ for(var CONST in self.STORAGE_CONST){ var constName = self.STORAGE_CONST[ CONST ]; newRow.values[ constName ] = _parseStorageRowType(self.info.storage[ row ][ key ], constName); newRow.keys[ constName ] = _parseStorageRowType(key, constName); } newRow.values.state = _defineDefaultState(newRow.values.string, newRow.values.number, newRow.values.address); newRow.keys.state = _defineDefaultState(newRow.keys.string, newRow.keys.number, newRow.keys.address); rows.push(newRow); } } } } return rows; }; var _stopSocket = function () { socket.emit('unsubscribe', 'siriusd/addresstxid', [addrStr]); }; socket.on('connect', function() { _startSocket(); }); $scope.$on('$destroy', function(){ _stopSocket(); }); self.params = $routeParams; self.findOne = function() { $rootScope.currentAddr = addrStr; _startSocket(); ERC20AddressBalances.query({ balanceAddress: addrStr }, function (balances) { if (balances && balances.length) { self.balances = balances.map(function (balance) { if (balance.contract) { balance.contract.contract_address_base = Contracts.getBitAddressFromContractAddress(balance.contract.contract_address); } return balance; }); } }); Address.get({ addrStr: addrStr }, function(address) { $rootScope.titleDetail = address.addrStr.substring(0, 7) + '...'; $rootScope.flashMessage = null; self.address = address; var ethAddress = Contracts.getEthAddressFromBitAddress(addrStr); if (ethAddress) { ERC20ContractInfo.get({ contractAddress: ethAddress }, function (data) { if (data) { self.erc20ContractInfo = data; } }); ContractsInfo.get({ contractAddressStr: ethAddress }, function (info) { if (info) { self.info = info; self.opcodesStr = Contracts.getContractOpcodesString(info.code); self.storage.rows = _formStorageInfo(); self.storage.storageLength = Object.keys(info.storage).length; self.storage.viewRows = Constants.STORAGE_ROWS; } }, function (e) { console.log('e', e); }); } }, function(e) { if (e.status === 400) { $rootScope.flashMessage = 'Invalid Address: ' + addrStr; } else if (e.status === 503) { $rootScope.flashMessage = 'Backend Error. ' + e.data; } else { $rootScope.flashMessage = 'Address Not Found'; } $location.path('/'); }); }; self.toggleStorageRowView = function(index, stateType) { var currentStateNumber = self.storageViews.indexOf(self.storage.rows[ index ][ stateType ].state); self.storage.rows[ index ][ stateType ].state = self.storageViews[ (currentStateNumber + 1) % self.storageViews.length ]; }; self.showMoreStorageRows = function(limit){ self.storage.viewRows = limit; }; //TODO:: outside click self.tokenDropdownOpen = false; self.toggleDropdownTokenTracker = function() { self.tokenDropdownOpen = !self.tokenDropdownOpen; }; }); // Source: public/src/js/controllers/blocks.js angular.module('insight.blocks').controller('BlocksController', function($scope, $rootScope, $routeParams, $location, moment, Block, Blocks, BlockByHeight) { var self = this; self.loading = false; self.date = null; self.datepicker = { date: null, format: 'yyyy-MM-dd', isOpened : false, dateOptions : { startingDay: 1, maxDate: new Date(), minDate: new Date(0), } }; if ($routeParams.blockHeight) { BlockByHeight.get({ blockHeight: $routeParams.blockHeight }, function(hash) { $location.path('block/' + hash.blockHash); }, function() { $rootScope.flashMessage = 'Bad Request'; $location.path('/'); }); } $scope.$watch(function () { return self.date; }, function(newValue, oldValue, scope) { if (newValue !== oldValue && scope.BC.datepicker.isOpened) { self.datepicker.date = newValue.getTime(); $location.path('blocks-date/' + moment(newValue).format('YYYY-MM-DD')); } }); self.openDatepicker = function(e) { e.preventDefault(); e.stopPropagation(); self.datepicker.isOpened = true; }; self.disableDatepicker = function (data) { var date = data.date, mode = data.mode; return mode === 'day' && (date.getDay() === 0 || date.getDay() === 6); }; self.loadList = function() { self.loading = true; if ($routeParams.blockDate) { self.detail = 'On ' + $routeParams.blockDate; } if ($routeParams.startTimestamp) { var d = new Date($routeParams.startTimestamp * 1000); var m = d.getMinutes(); if (m < 10){ m = '0' + m }; self.before = ' before ' + d.getHours() + ':' + m; } $rootScope.titleDetail = self.detail; Blocks.get({ blockDate: $routeParams.blockDate, startTimestamp: $routeParams.startTimestamp }, function(res) { self.loading = false; var date = new Date(res.pagination.current); self.date = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); self.datepicker.date = self.date.getTime(); self.blocks = res.blocks; self.pagination = res.pagination; }); }; self.findOne = function() { self.loading = true; Block.get({ blockHash: $routeParams.blockHash }, function(block) { $rootScope.titleDetail = block.height; $rootScope.flashMessage = null; self.loading = false; self.block = block; }, function(e) { if (e.status === 400) { $rootScope.flashMessage = 'Invalid Transaction ID: ' + $routeParams.txId; } else if (e.status === 503) { $rootScope.flashMessage = 'Backend Error. ' + e.data; } else { $rootScope.flashMessage = 'Block Not Found'; } $location.path('/'); }); }; self.calcDatesDifference = function() { var present = new Date(); var presentDate = moment.utc([present.getUTCFullYear(), present.getUTCMonth(), present.getUTCDate()]); var currentDate = moment.utc(self.pagination.current); return currentDate.from(presentDate); } self.params = $routeParams; }); // Source: public/src/js/controllers/charts.js angular.module('insight.charts').controller('ChartsController', function($scope, $routeParams, BigNumber, StatisticsBalanceIntervals, StatisticsByDaysSupply, StatisticsRicherThan, MarketsInfo, getSocket, $q, StatisticChart) { var self = this; self.chartDays = $routeParams.days ? $routeParams.days : 60; var statisticChart = new StatisticChart(self.chartDays); statisticChart.load(StatisticsByDaysSupply, 'sum', 'supply', false); $scope.$on('chart-create', function (evt, chart) { if (chart.chart.canvas.id === 'line') { statisticChart.changeChartColor(chart); chart.update(); } }); self.chartOptions = statisticChart.chartOptions; self.daysButtons = statisticChart.daysButtons; self.balanceIntervals = []; self.marketsInfo = null; self.richerThanIntervals = []; var socket = getSocket($scope); self.init = function() { _getInfo(); _getRicherThan(); }; var _getRicherThan = function () { return StatisticsRicherThan.query(function (intervals) { self.richerThanIntervals = intervals; }) }; var _getInfo = function() { return $q.all([StatisticsBalanceIntervals.query().$promise, MarketsInfo.get().$promise]).then(function (results) { if (results[0] && results[1]) { self.marketsInfo = results[1]; var items = results[0], intervals = [], countAddresses = 0, maxCountAddresses = 0, sumCoins = new BigNumber(0), maxSumCoins = new BigNumber(0); items.forEach(function (interval) { var sumBN = new BigNumber(interval.sum.toString()); countAddresses += interval.count; if (interval.count > maxCountAddresses) { maxCountAddresses = interval.count; } sumCoins = sumCoins.plus(sumBN); if (maxSumCoins.lt(sumBN)) { maxSumCoins = new BigNumber(sumBN); } }); items.forEach(function (interval) { var addressesPercent = interval.count && countAddresses ? interval.count / countAddresses * 100 : 0; var addressesRelativePercent = interval.count && maxCountAddresses ? interval.count / maxCountAddresses * 100 : 0; var sumBN = new BigNumber(interval.sum.toString()); var coinsPercent = sumBN.gt(0) && sumCoins.gt(0) ? sumBN.dividedBy(sumCoins).mul(100) : new BigNumber(0); var coinsRelativePercent = sumBN.gt(0) && maxSumCoins.gt(0) ? sumBN.dividedBy(maxSumCoins).mul(100) : new BigNumber(0); intervals.push({ min: interval.min, max: interval.max, count: interval.count, sum: sumBN.toString(10), addressesPercent: addressesPercent.toFixed(2), addressesRelativePercent: addressesRelativePercent.toFixed(2), coinsPercent: coinsPercent.toNumber().toFixed(2), coinsRelativePercent: coinsRelativePercent.toNumber().toFixed(2) }); }); self.balanceIntervals = intervals; } }); }; socket.on('markets_info', function(marketsInfo) { self.marketsInfo = marketsInfo; }); }); // Source: public/src/js/controllers/connection.js angular.module('insight.connection').controller('ConnectionController', function($scope, $window, Status, getSocket, PeerSync) { // Set initial values $scope.apiOnline = true; $scope.serverOnline = true; $scope.clienteOnline = true; var socket = getSocket($scope); // Check for the node server connection socket.on('connect', function() { $scope.serverOnline = true; socket.on('disconnect', function() { $scope.serverOnline = false; }); }); // Check for the api connection $scope.getConnStatus = function() { PeerSync.get({}, function(peer) { $scope.apiOnline = peer.connected; $scope.host = peer.host; $scope.port = peer.port; }, function() { $scope.apiOnline = false; }); }; socket.emit('subscribe', 'sync'); socket.on('status', function(sync) { $scope.sync = sync; $scope.apiOnline = (sync.status !== 'aborted' && sync.status !== 'error'); }); // Check for the client conneciton $window.addEventListener('offline', function() { $scope.$apply(function() { $scope.clienteOnline = false; }); }, true); $window.addEventListener('online', function() { $scope.$apply(function() { $scope.clienteOnline = true; }); }, true); }); // Source: public/src/js/controllers/contracts.js angular.module('insight.contracts').controller('ContractsController', function($scope, $rootScope, $routeParams, $location, Contracts) { try { var addrStr = Contracts.getBitAddressFromContractAddress($routeParams.contractAddressStr); $location.path('address/' + addrStr); return false; } catch (e) { $rootScope.flashMessage = 'Invalid Address: ' + $routeParams.contractAddressStr; $location.path('/'); return false; } }); // Source: public/src/js/controllers/currency.js angular.module('insight.currency').controller('CurrencyController', function($scope, $rootScope, Currency, Constants, BigNumber, $filter) { var self = this; $rootScope.currency = { symbol : Constants.DEFAULT_CURRENCY, factor : 1, bitstamp : 0 }; $rootScope.token = {}; var _roundFloat = function(x, n) { if(!parseInt(n, 10) || !parseFloat(x)) n = 0; return Math.round(x * Math.pow(10, n)) / Math.pow(10, n); }; $rootScope.currency.getConvertion = function(value) { value = Number(value); if (!isNaN(value) && typeof value !== 'undefined' && value !== null) { if (value === 0.00000000) return '0 ' + $rootScope.currency.symbol; // fix value to show var response; if ($rootScope.currency.symbol === Constants.CURRENCY.USD) { response = _roundFloat((value * $rootScope.currency.factor), 2); } else if ($rootScope.currency.symbol === Constants.CURRENCY.mBTC) { $rootScope.currency.factor = 1000; response = _roundFloat((value * $rootScope.currency.factor), 5); } else if ($rootScope.currency.symbol === Constants.CURRENCY.bits) { $rootScope.currency.factor = 1000000; response = _roundFloat((value * $rootScope.currency.factor), 2); } else { $rootScope.currency.factor = 1; response = value; } // prevent sci notation if (response < 1e-7) { response = response.toFixed(8); } return $filter('numeraljs')(response, '0,0[.][00000000]') + ' ' + $rootScope.currency.symbol; } return 'value error'; }; $rootScope.token.convertDecimals = function (amount, decimals) { if (!amount) { return 0; } var valueBN = new BigNumber(amount); return valueBN.dividedBy('1e' + (decimals ? decimals : 0)).toString(10); }; self.setCurrency = function(currency) { $rootScope.currency.symbol = Constants.CURRENCY[ currency ]; localStorage.setItem('insight-currency', Constants.CURRENCY[ currency ]); if (currency === 'USD') { Currency.get({}, function(res) { $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; }); } else if (currency === 'mBTC') { $rootScope.currency.factor = 1000; } else if (currency === 'bits') { $rootScope.currency.factor = 1000000; } else { $rootScope.currency.factor = 1; } }; // Get initial value Currency.get({}, function(res) { $rootScope.currency.factor = $rootScope.currency.bitstamp = res.data.bitstamp; }); }); // Source: public/src/js/controllers/footer.js angular.module('insight.system').controller('FooterController', function($scope, $route, $templateCache, gettextCatalog, amMoment, Version) { var _getVersion = function() { Version.get({}, function(res) { $scope.version = res.version; }); }; $scope.version = _getVersion(); }); // Source: public/src/js/controllers/header.js angular.module('insight.system').controller('HeaderController', function($scope, $rootScope, $route, gettextCatalog, amMoment, getSocket, Block, $templateCache, Constants, $location) { var self = this; var socket = getSocket($scope); self.defaultLanguage = Constants.DEFAULT_LANGUAGE; self.menu = _getMenu(); self.isActiveMenuItem = function (item) { return $location.path().search(item) !== -1 ? 'active': '' }; function _getMenu() { return [ { 'title': gettextCatalog.getString('Blocks'), 'link': 'blocks', 'active_part': '/block' }, { 'title': gettextCatalog.getString('Status'), 'link': 'status', 'active_part': '/status' }, { 'title': gettextCatalog.getString('Stats'), 'link': 'stats', 'active_part': '/stats' }, { 'title': gettextCatalog.getString('Circulation'), 'link': 'charts', 'active_part': '/charts' }, { 'title': gettextCatalog.getString('Rich List'), 'link': 'rich-list', 'active_part': '/rich-list' }, { 'title': gettextCatalog.getString('Tokens'), 'link': 'tokens/search', 'active_part': '/token' } ]; } self.availableLanguages = [ { name: gettextCatalog.getString('Deutsch'), isoCode: 'de_DE' }, { name: gettextCatalog.getString('English'), isoCode: 'en' }, { name: gettextCatalog.getString('Spanish'), isoCode: 'es' }, { name: gettextCatalog.getString('Japanese'), isoCode: 'ja' } ]; var _getBlock = function(hash) { Block.get({ blockHash: hash }, function(res) { self.totalBlocks = res.height; }); }; socket.on('connect', function() { socket.emit('subscribe', 'inv'); socket.on('block', function(block) { var blockHash = block.toString(); _getBlock(blockHash); }); }); self.setLanguage = function(isoCode) { var currentPageTemplate = $route.current.templateUrl; gettextCatalog.currentLanguage = self.defaultLanguage = isoCode; amMoment.changeLocale(isoCode); localStorage.setItem('insight-language', isoCode); $templateCache.remove(currentPageTemplate); self.menu = _getMenu(); $route.reload(); }; $rootScope.isCollapsed = true; }); // Source: public/src/js/controllers/index.js angular.module('insight.system').controller('IndexController', function($scope, $rootScope, $window, $timeout, moment, getSocket, Blocks, TransactionsByDays, Constants, Status, $q, StatisticsTotalSupply, MarketsInfo) { var self = this; var socket = getSocket($scope); self.blockchainInfo = null; self.marketsInfo = { price_usd: 0, price_btc: 0, market_cap_usd: 0 }; self.txs = []; self.blocks = []; self.chartDays = Constants.CHART_DAYS; self.rewardCurrency = Constants.CURRENCY.SIRX; self.scrollConfig = { autoHideScrollbar: false, axis: 'y', theme: 'custom', advanced: { updateOnContentResize: true }, scrollInertia: 0, callbacks: { onBeforeUpdate: function() { var maxHeight = parseInt($window.getComputedStyle(this).maxHeight), list = this.getElementsByClassName('mCSB_container'), heightList = list[0].clientHeight; if (heightList > maxHeight) { this.style.height = maxHeight + 'px'; } else { this.style.height = heightList + 'px'; } } } }; self.chartOptions = { series : [ 'Transactions' ], datasetOverride : [{ yAxisID: 'y-axis-1' , borderColor: '#2e9ad0', borderWidth: 1, fill: false, pointBorderColor: '#2e9ad0', pointBackgroundColor: '#2e9ad0', pointBorderWidth: 1, pointHoverBackgroundColor: '#e75647', pointHoverBorderColor: '#e75647', pointHoverBorderWidth: 1, pointHitRadius: 10, pointStyle: 'rect', lineTension: 0 }], options : { tooltips:{ backgroundColor: '#2e9ad0', titleFontFamily: 'SimplonMono', titleFontSize: 12, titleFontStyle: '500', titleFontColor: '#232328', bodyFontFamily: 'SimplonMono', bodyFontSize: 12, bodyFontStyle: '400', bodyFontColor: '#232328', caretSize: 5, cornerRadius: 0, displayColors: false }, scales: { yAxes: [{ id: 'y-axis-1', type: 'linear', display: true, position: 'left', gridLines: { color: '#26475b', drawBorder: false, drawTicks: true, offsetGridLines: true }, ticks: { fontColor:'#2e9ad0', fontFamily: 'SimplonMono', fontSize: 14, padding: 25, callback: function(value) { return value + ' t'; } } }], xAxes: [{ gridLines: { color: '#26475b', drawBorder: false, drawOnChartArea: false, drawTicks: true, zeroLineColor: '#26475b' }, ticks: { fontColor:'#2e9ad0', fontSize: 10, fontFamily: 'SimplonMono' } }] } } }; var _getBlocks = function() { Blocks.get({ limit: Constants.BLOCKS_DISPLAYED }, function(res) { self.blocks = res.blocks; self.blocksLength = res.length; }); }; var socketRequestTimer = null; var _startSocket = function() { socket.emit('subscribe', 'inv'); socket.on('tx', function(tx) { tx.createTime = Date.now(); self.txs.unshift(tx); if (self.txs.length > Constants.TRANSACTION_DISPLAYED) { self.txs.length = Constants.TRANSACTION_DISPLAYED; } }); socket.on('info', function(data) { self.blockchainInfo = data.info; self.blockchainInfo.supply = data.supply; self.blockchainInfo.stakingInfo = data.stakingInfo; }); socket.on('block', function() { clearTimeout(socketRequestTimer); socketRequestTimer = setTimeout(function () { _getBlocks(); }, Math.random() * 2000); //prevent waterfall }); socket.on('markets_info', function(marketsInfo) { self.marketsInfo = marketsInfo; }); }; socket.on('connect', function() { _startSocket(); }); self.getListOfTransactions = function() { TransactionsByDays.query({ days: self.chartDays }, function(response){ while(response.length < self.chartDays){ response.push({ date : moment().subtract(self.chartDays - (self.chartDays - response.length), 'days').format('YYYY-MM-DD'), transaction_count: 0 }); } self.lastTransactionsList = response.reverse(); self.chartOptions.labels = self.lastTransactionsList.map(function(item){ return moment(item.date).format('MM/DD'); }); self.chartOptions.data = [ self.lastTransactionsList.map(function(item){ return item.transaction_count; })]; }); }; var _getInfo = function() { $q.all([Status.get({ q: 'getInfo' }).$promise, StatisticsTotalSupply.get({format: 'object'}).$promise, Status.get({ q: 'getStakingInfo' }).$promise]).then(function (results) { if (results[0] && results[1] && results[2]) { self.blockchainInfo = results[0].info; self.blockchainInfo.stakingInfo = results[2]; self.blockchainInfo.supply = results[1].supply; } }); }; var _getMarketsInfo = function () { return MarketsInfo.get({}, function(response) { if (response) { self.marketsInfo = response; } }); }; self.index = function() { _getInfo(); _getMarketsInfo(); _getBlocks(); _startSocket(); }; }); // Source: public/src/js/controllers/messages.js angular.module('insight.messages').controller('VerifyMessageController', function($scope, $http) { $scope.message = { address: '', signature: '', message: '' }; $scope.verification = { status: 'unverified', // ready|loading|verified|error result: null, error: null, address: '' }; $scope.verifiable = function() { return ($scope.message.address && $scope.message.signature && $scope.message.message); }; $scope.verify = function() { $scope.verification.status = 'loading'; $scope.verification.address = $scope.message.address; $http.post(window.apiPrefix + '/messages/verify', $scope.message) .success(function(data, status, headers, config) { if(typeof(data.result) != 'boolean') { // API returned 200 but result was not true or false $scope.verification.status = 'error'; $scope.verification.error = null; return; } $scope.verification.status = 'verified'; $scope.verification.result = data.result; }) .error(function(data, status, headers, config) { $scope.verification.status = 'error'; $scope.verification.error = data; }); }; // Hide the verify status message on form change var unverify = function() { $scope.verification.status = 'unverified'; }; $scope.$watch('message.address', unverify); $scope.$watch('message.signature', unverify); $scope.$watch('message.message', unverify); }); // Source: public/src/js/controllers/richList.js angular.module('insight.richList').controller('RichListController', function($scope, $routeParams, StatisticsRichestList) { var self = this; self.items = []; self.loaded = false; self.init = function() { StatisticsRichestList.query({}, function (items) { self.items = items; self.loaded = true; }); }; }); // Source: public/src/js/controllers/scanner.js angular.module('insight.system').controller('ScannerController', function($scope, $rootScope, $modalInstance, Global) { $scope.global = Global; // Detect mobile devices var isMobile = { Android: function() { return navigator.userAgent.match(/Android/i); }, BlackBerry: function() { return navigator.userAgent.match(/BlackBerry/i); }, iOS: function() { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }, Opera: function() { return navigator.userAgent.match(/Opera Mini/i); }, Windows: function() { return navigator.userAgent.match(/IEMobile/i); }, any: function() { return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); } }; navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL; $scope.isMobile = isMobile.any(); $scope.scannerLoading = false; var $searchInput = angular.element(document.getElementById('search')), cameraInput, video, canvas, $video, context, localMediaStream; var _scan = function(evt) { if ($scope.isMobile) { $scope.scannerLoading = true; var files = evt.target.files; if (files.length === 1 && files[0].type.indexOf('image/') === 0) { var file = files[0]; var reader = new FileReader(); reader.onload = (function(theFile) { return function(e) { var mpImg = new MegaPixImage(file); mpImg.render(canvas, { maxWidth: 200, maxHeight: 200, orientation: 6 }); setTimeout(function() { qrcode.width = canvas.width; qrcode.height = canvas.height; qrcode.imagedata = context.getImageData(0, 0, qrcode.width, qrcode.height); try { qrcode.decode(); } catch (e) { alert(e); } }, 1500); }; })(file); // Read in the file as a data URL reader.readAsDataURL(file); } } else { if (localMediaStream) { context.drawImage(video, 0, 0, 300, 225); try { qrcode.decode(); } catch(e) { //qrcodeError(e); } } setTimeout(_scan, 500); } }; var _successCallback = function(stream) { video.src = (window.URL && window.URL.createObjectURL(stream)) || stream; localMediaStream = stream; video.play(); setTimeout(_scan, 1000); }; var _scanStop = function() { $scope.scannerLoading = false; $modalInstance.close(); if (!$scope.isMobile) { if (localMediaStream.stop) localMediaStream.stop(); localMediaStream = null; video.src = ''; } }; var _videoError = function(err) { console.log('Video Error: ' + JSON.stringify(err)); _scanStop(); }; qrcode.callback = function(data) { _scanStop(); var str = (data.indexOf('sirius:') === 0) ? data.substring(8) : data; console.log('QR code detected: ' + str); $searchInput .val(str) .triggerHandler('change') .triggerHandler('submit'); }; $scope.cancel = function() { _scanStop(); }; $modalInstance.opened.then(function() { $rootScope.isCollapsed = true; // Start the scanner setTimeout(function() { canvas = document.getElementById('qr-canvas'); context = canvas.getContext('2d'); if ($scope.isMobile) { cameraInput = document.getElementById('qrcode-camera'); cameraInput.addEventListener('change', _scan, false); } else { video = document.getElementById('qrcode-scanner-video'); $video = angular.element(video); canvas.width = 300; canvas.height = 225; context.clearRect(0, 0, 300, 225); navigator.getUserMedia({video: true}, _successCallback, _videoError); } }, 500); }); }); // Source: public/src/js/controllers/search.js angular.module('insight.search').controller('SearchController', function($location, $timeout, Block, Transaction, Address, BlockByHeight, ERC20ContractInfo, Contracts) { var self = this; self.loading = false; var _badQuery = function() { self.badQuery = true; $timeout(function() { self.badQuery = false; }, 2000); }; var _resetSearch = function() { self.q = ''; self.loading = false; }; self.search = function() { var q = self.q.trim(); self.badQuery = false; self.loading = true; Block.get({ blockHash: q }, function() { _resetSearch(); $location.path('block/' + q); }, function() { //block not found, search on TX Transaction.get({ txId: q }, function() { _resetSearch(); $location.path('tx/' + q); }, function() { //tx not found, search on Address var bitAddress = q; Address.get({ addrStr: bitAddress }, function() { _resetSearch(); $location.path('address/' + bitAddress); }, function() { // block by height not found if (isFinite(q)) { // ensure that q is a finite number. A logical height value. BlockByHeight.get({ blockHeight: q }, function(hash) { _resetSearch(); $location.path('block/' + hash.blockHash); }, function() { //not found, fail :( self.loading = false; _badQuery(); }); } else { ERC20ContractInfo.get({ contractAddress: q }, function() { _resetSearch(); $location.path('token/' + q); }, function () { self.loading = false; _badQuery(); }); } }); }); }); }; }); // Source: public/src/js/controllers/sendRawTransaction.js angular.module('insight.transactions').controller('SendRawTransactionController', function ($scope, $http, $filter, SendRawTransaction, lodash) { var $cachedTextarea = null; var timeoutId = null; $scope.status = 'ready'; // ready|sent|error $scope.error = null; $scope.isEmpty = false; $scope.rawTransaction; $scope.txid = ''; $scope.jqueryScrollbarOptions = { }; $scope.send = function () { clearState(); if (!validateRawTransaction()) { return; } var postData = { rawtx: $scope.rawTransaction.trim(), }; SendRawTransaction.send(postData, function (successfullResponse) { if (typeof (successfullResponse.txid) != 'string') { // API returned 200 but the format is not known $scope.status = 'error'; $scope.error = ': the transaction was sent but no transaction id was got back'; return; } $scope.status = 'sent'; $scope.txid = successfullResponse.txid; clearDataAfterSuccessfullSend(); }, function (errorResponse) { var data = errorResponse.data; $scope.status = 'error'; if (data) { $scope.error = ': ' + data; } else { $scope.error = "no error message given (connection error?)" } }); }; $scope.isStatusError = function () { return $scope.status === 'error' ? true : false; } $scope.checkIsEmpty = function () { return $scope.isEmpty; } $scope.isStatusSent = function () { return $scope.status === 'sent' ? true : false; } $scope.$on('$destroy', function () { clearState(); }); var clearState = function () { $scope.status = 'ready'; $scope.isEmpty = false; $scope.error = null; $scope.txid = ''; clearTimeout(timeoutId); } var getElementByClassName = function (className) { return angular.element(className); } var validateRawTransaction = function () { var rawTrx = $scope.rawTransaction; if (!rawTrx) { $scope.isEmpty = true; return false; } if (!lodash.isString(rawTrx) || !(/^[0-9a-fA-F]+$/.test(rawTrx))) { $scope.status = 'error'; $scope.error = ': the transaction hex is not valid'; return false; } return true; } var clearDataAfterSuccessfullSend = function () { $scope.rawTransaction = null; timeoutId = setTimeout(function() { clearState(); $scope.$apply(); }, 2 * 60 * 1000); } }); // Source: public/src/js/controllers/statistics.js angular.module('insight.statistics').controller('StatisticsController', function($scope, $routeParams, Statistics, StatisticsByDaysTransactions, StatisticsByDaysOutputs, StatisticsByDaysFees, StatisticsByDaysDifficulty, StatisticsByDaysStakes, Statistics24Hours, gettextCatalog, $filter, Constants, StatisticChart, MarketsInfo) { var self = this, factories = { 'transactions' : { factory : StatisticsByDaysTransactions, field : 'transaction_count' }, 'outputs' : { factory : StatisticsByDaysOutputs, field : 'sum' }, 'fees' : { factory : StatisticsByDaysFees, field : 'fee' }, 'difficulty' : { factory : StatisticsByDaysDifficulty, field : 'sum' }, 'stakes' : { factory : StatisticsByDaysStakes, field : 'sum' } }; self.chartText = { fees: gettextCatalog.getString('The total value of all transaction fees paid to miners (not including the coinbase value of block rewards).'), transactions: gettextCatalog.getString('The number of daily confirmed Sirius transactions.'), outputs: gettextCatalog.getString('The total value of all transaction outputs per day (includes coins returned to the sender as change).'), difficulty: gettextCatalog.getString('A relative measure of how difficult it is to find a new block. The difficulty is adjusted periodically as a function of how much hashing power has been deployed by the network of miners.'), stakes: gettextCatalog.getString('') }; self.chartDays = $routeParams.days; self.chartType = $routeParams.type; self.marketCurrency = Constants.CURRENCY.USD; self.marketPrice = 0; var statisticChart = new StatisticChart(self.chartDays); self.chartOptions = statisticChart.chartOptions; self.daysButtons = statisticChart.daysButtons; $scope.$on('chart-create', function (evt, chart) { if (chart.chart.canvas.id === 'line') { statisticChart.changeChartColor(chart); chart.update(); } }); self.getDifficulties = function(){ statisticChart.load(factories[ $routeParams.type ].factory, factories[ $routeParams.type ].field, $routeParams.type); }; self.get24HoursStats = function() { Statistics24Hours.get(function(response) { self.statsTotal24 = response; }); MarketsInfo.get({}, function(response) { if (response && response.price_usd) { self.marketPrice = response.price_usd; } }); }; }); // Source: public/src/js/controllers/status.js angular.module('insight.status').controller('StatusController', function($scope, Status, Sync, getSocket) { var self = this; var socket = getSocket($scope); self.getStatus = function(q) { Status.get({ q: 'get' + q }, function(d) { self.loaded = 1; angular.extend(self, d); }, function(e) { self.error = 'API ERROR: ' + e.data; }); }; var _onSyncUpdate = function(sync) { if(!sync.startTs){ sync.startTs = Date.now(); } self.sync = sync; }; var _startSocket = function () { socket.emit('subscribe', 'sync'); socket.on('status', function(sync) { _onSyncUpdate(sync); }); }; socket.on('connect', function() { _startSocket(); }); self.getSync = function() { _startSocket(); Sync.get({}, function(sync) { _onSyncUpdate(sync); }, function(e) { self.sync = { error: 'Could not get sync information' + e.toString() }; }); }; }); // Source: public/src/js/controllers/token.js angular.module('insight.token').controller('TokenController', function($routeParams, $rootScope, $location, ERC20ContractInfo, ERC20Transfers, ERC20AddressBalances, ERC20Holders, ContractsRepository, SolidityCoder, Web3Utils, Contracts, BigNumber) { if (!Web3Utils.isAddress($routeParams.address) && !Contracts.isValidSiriusAddress($routeParams.address)) { $rootScope.flashMessage = 'Invalid Address: ' + $routeParams.address; $location.path('e404').replace(); return false; } var contractEthAddress = $routeParams.address; if (!Web3Utils.isAddress(contractEthAddress)) { contractEthAddress = Contracts.getEthAddressFromBitAddress($routeParams.address); $location.path('token/' + contractEthAddress).replace(); return false; } var contractBase58Address = Contracts.getBitAddressFromContractAddress($routeParams.address); var self = this; var BALANCE_OF_METHOD_HASH = '70a08231'; var ALLOWANCE_METHOD_HASH = 'dd62ed3e'; self.tokenInfo = {}; self.transfers = {}; self.holders = {}; self.filterByAddress = null; if ($routeParams.a) { if (Web3Utils.isAddress($routeParams.a)) { self.filterByAddress = Contracts.getBitAddressFromContractAddress($routeParams.a); } if (Contracts.isValidSiriusAddress($routeParams.a)) { self.filterByAddress = $routeParams.a; } } self.addressBalance = null; self.readSmartContractTab = { balanceOf: { owner_address: '', inProcess: false, owner_error: '', balance: 0, requested_address: '', process_address: '' }, allowance: { owner_address: '', spender_address: '', inProcess: false, owner_error: '', spender_error: '', owner_requested_address: '', owner_process_address: '', spender_requested_address: '', spender_process_address: '' } }; self.contractAddress = $routeParams.address; self.tab = $routeParams.tab && ['transfers', 'holders', 'read-smart-contract'].indexOf($routeParams.tab) !== -1 ? $routeParams.tab : 'transfers'; var _loadTabContent = function(offset) { switch(self.tab){ case 'transfers': { _getTransfers(offset ? offset : 0); break; } case 'holders': { _getHolders(offset ? offset : 0); break; } case 'read-smart-contract': { break; } } }; self.getPercent = function (total, amount) { var amountBN = new BigNumber(amount); return amountBN.dividedBy(total).mul(100).toString(10); }; var _getTransfers = function(offset) { ERC20Transfers.get({ address: contractEthAddress, offset: offset, 'addresses[]': (self.filterByAddress) ? self.filterByAddress: null }).$promise.then(function (trList) { self.transfers = trList; self.transfers.pages = self.transfers.count && self.transfers.limit ? Math.ceil(self.transfers.count / self.transfers.limit) : 0; }); }; var _getHolders = function(offset) { return ERC20Holders.get({ address: contractEthAddress, offset: offset }).$promise.then(function (holderList) { self.holders = holderList; self.holders.pages = self.holders.count && self.holders.limit ? Math.ceil(self.holders.count / self.holders.limit) : 0; }); }; var _loadTokenInfo = function() { ERC20ContractInfo.get({ contractAddress: contractEthAddress, address: self.filterByAddress ? self.filterByAddress : null }, function (info) { if (info) { self.tokenInfo = info; try { self.tokenInfo.contract_address_base = Contracts.getBitAddressFromContractAddress(self.tokenInfo.contract_address); } catch (e) { console.log('Error convert', self.tokenInfo); } } }); if (self.filterByAddress) { ERC20AddressBalances.get({ contractAddress: contractEthAddress, balanceAddress: self.filterByAddress }).$promise.then(function (balance) { self.addressBalance = balance; }).catch(function (err) { console.log(err); }) } }; self.init = function() { _loadTokenInfo(); _loadTabContent(); }; self.paginate = function(offset) { if (self[self.tab].limit && self[self.tab].pages > offset / self[self.tab].limit && offset >= 0 && self[self.tab].offset !== offset) { _loadTabContent(offset); } }; self.setTab = function(tabName) { if (self.tab === tabName) { return; } self.tab = tabName; $location.path('token/' + $routeParams.address + '/' + tabName, false); _loadTabContent(); }; var getEthConvertedAddress = function (address) { try { if (Contracts.isValidSiriusAddress(address)) { var ethAddress = Contracts.getEthAddressFromBitAddress(a