sirius-explorer
Version:
An open-source front-end for the Insight API.
1,864 lines (1,422 loc) • 121 kB
JavaScript
// 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