Merge branch 'master' into mononaut/confirmed-tx-status
This commit is contained in:
		
						commit
						90634c4343
					
				@ -40,7 +40,9 @@
 | 
			
		||||
    "PORT": 8332,
 | 
			
		||||
    "USERNAME": "mempool",
 | 
			
		||||
    "PASSWORD": "mempool",
 | 
			
		||||
    "TIMEOUT": 60000
 | 
			
		||||
    "TIMEOUT": 60000,
 | 
			
		||||
    "COOKIE": false,
 | 
			
		||||
    "COOKIE_PATH": "/path/to/bitcoin/.cookie"
 | 
			
		||||
  },
 | 
			
		||||
  "ELECTRUM": {
 | 
			
		||||
    "HOST": "127.0.0.1",
 | 
			
		||||
@ -60,7 +62,9 @@
 | 
			
		||||
    "PORT": 8332,
 | 
			
		||||
    "USERNAME": "mempool",
 | 
			
		||||
    "PASSWORD": "mempool",
 | 
			
		||||
    "TIMEOUT": 60000
 | 
			
		||||
    "TIMEOUT": 60000,
 | 
			
		||||
    "COOKIE": false,
 | 
			
		||||
    "COOKIE_PATH": "/path/to/bitcoin/.cookie"
 | 
			
		||||
  },
 | 
			
		||||
  "DATABASE": {
 | 
			
		||||
    "ENABLED": true,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										14
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								backend/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -12,7 +12,7 @@
 | 
			
		||||
        "@babel/core": "^7.23.2",
 | 
			
		||||
        "@mempool/electrum-client": "1.1.9",
 | 
			
		||||
        "@types/node": "^18.15.3",
 | 
			
		||||
        "axios": "~1.5.0",
 | 
			
		||||
        "axios": "~1.6.1",
 | 
			
		||||
        "bitcoinjs-lib": "~6.1.3",
 | 
			
		||||
        "crypto-js": "~4.2.0",
 | 
			
		||||
        "express": "~4.18.2",
 | 
			
		||||
@ -2325,9 +2325,9 @@
 | 
			
		||||
      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/axios": {
 | 
			
		||||
      "version": "1.5.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
 | 
			
		||||
      "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
 | 
			
		||||
      "version": "1.6.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
 | 
			
		||||
      "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "follow-redirects": "^1.15.0",
 | 
			
		||||
        "form-data": "^4.0.0",
 | 
			
		||||
@ -9415,9 +9415,9 @@
 | 
			
		||||
      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
 | 
			
		||||
    },
 | 
			
		||||
    "axios": {
 | 
			
		||||
      "version": "1.5.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
 | 
			
		||||
      "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
 | 
			
		||||
      "version": "1.6.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz",
 | 
			
		||||
      "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "follow-redirects": "^1.15.0",
 | 
			
		||||
        "form-data": "^4.0.0",
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,7 @@
 | 
			
		||||
    "@babel/core": "^7.23.2",
 | 
			
		||||
    "@mempool/electrum-client": "1.1.9",
 | 
			
		||||
    "@types/node": "^18.15.3",
 | 
			
		||||
    "axios": "~1.5.0",
 | 
			
		||||
    "axios": "~1.6.1",
 | 
			
		||||
    "bitcoinjs-lib": "~6.1.3",
 | 
			
		||||
    "crypto-js": "~4.2.0",
 | 
			
		||||
    "express": "~4.18.2",
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,9 @@
 | 
			
		||||
    "PORT": 15,
 | 
			
		||||
    "USERNAME": "__CORE_RPC_USERNAME__",
 | 
			
		||||
    "PASSWORD": "__CORE_RPC_PASSWORD__",
 | 
			
		||||
    "TIMEOUT": 1000
 | 
			
		||||
    "TIMEOUT": 1000,
 | 
			
		||||
    "COOKIE": false,
 | 
			
		||||
    "COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__"
 | 
			
		||||
  },
 | 
			
		||||
  "ELECTRUM": {
 | 
			
		||||
    "HOST": "__ELECTRUM_HOST__",
 | 
			
		||||
@ -61,7 +63,9 @@
 | 
			
		||||
    "PORT": 17,
 | 
			
		||||
    "USERNAME": "__SECOND_CORE_RPC_USERNAME__",
 | 
			
		||||
    "PASSWORD": "__SECOND_CORE_RPC_PASSWORD__",
 | 
			
		||||
    "TIMEOUT": 2000
 | 
			
		||||
    "TIMEOUT": 2000,
 | 
			
		||||
    "COOKIE": false,
 | 
			
		||||
    "COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__"
 | 
			
		||||
  },
 | 
			
		||||
  "DATABASE": {
 | 
			
		||||
    "ENABLED": false,
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,9 @@ describe('Mempool Backend Config', () => {
 | 
			
		||||
        PORT: 8332,
 | 
			
		||||
        USERNAME: 'mempool',
 | 
			
		||||
        PASSWORD: 'mempool',
 | 
			
		||||
        TIMEOUT: 60000
 | 
			
		||||
        TIMEOUT: 60000,
 | 
			
		||||
        COOKIE: false,
 | 
			
		||||
        COOKIE_PATH: '/bitcoin/.cookie'
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      expect(config.SECOND_CORE_RPC).toStrictEqual({
 | 
			
		||||
@ -74,7 +76,9 @@ describe('Mempool Backend Config', () => {
 | 
			
		||||
        PORT: 8332,
 | 
			
		||||
        USERNAME: 'mempool',
 | 
			
		||||
        PASSWORD: 'mempool',
 | 
			
		||||
        TIMEOUT: 60000
 | 
			
		||||
        TIMEOUT: 60000,
 | 
			
		||||
        COOKIE: false,
 | 
			
		||||
        COOKIE_PATH: '/bitcoin/.cookie'
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      expect(config.DATABASE).toStrictEqual({
 | 
			
		||||
 | 
			
		||||
@ -32,4 +32,5 @@ export interface BitcoinRpcCredentials {
 | 
			
		||||
  user: string;
 | 
			
		||||
  pass: string;
 | 
			
		||||
  timeout: number;
 | 
			
		||||
  cookie?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ const nodeRpcCredentials: BitcoinRpcCredentials = {
 | 
			
		||||
  user: config.CORE_RPC.USERNAME,
 | 
			
		||||
  pass: config.CORE_RPC.PASSWORD,
 | 
			
		||||
  timeout: config.CORE_RPC.TIMEOUT,
 | 
			
		||||
  cookie: config.CORE_RPC.COOKIE ? config.CORE_RPC.COOKIE_PATH : undefined,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default new bitcoin.Client(nodeRpcCredentials);
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ const nodeRpcCredentials: BitcoinRpcCredentials = {
 | 
			
		||||
  user: config.SECOND_CORE_RPC.USERNAME,
 | 
			
		||||
  pass: config.SECOND_CORE_RPC.PASSWORD,
 | 
			
		||||
  timeout: config.SECOND_CORE_RPC.TIMEOUT,
 | 
			
		||||
  cookie: config.SECOND_CORE_RPC.COOKIE ? config.SECOND_CORE_RPC.COOKIE_PATH : undefined,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default new bitcoin.Client(nodeRpcCredentials);
 | 
			
		||||
 | 
			
		||||
@ -252,7 +252,11 @@ class DiskCache {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (rbfData?.rbf) {
 | 
			
		||||
        rbfCache.load(rbfData.rbf);
 | 
			
		||||
        rbfCache.load({
 | 
			
		||||
          txs: rbfData.rbf.txs.map(([txid, entry]) => ({ value: entry })),
 | 
			
		||||
          trees: rbfData.rbf.trees,
 | 
			
		||||
          expiring: rbfData.rbf.expiring.map(([txid, value]) => ({ key: txid, value })),
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      logger.warn('Failed to parse rbf cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e));
 | 
			
		||||
 | 
			
		||||
@ -53,6 +53,9 @@ class RbfCache {
 | 
			
		||||
  private expiring: Map<string, number> = new Map();
 | 
			
		||||
  private cacheQueue: CacheEvent[] = [];
 | 
			
		||||
 | 
			
		||||
  private evictionCount = 0;
 | 
			
		||||
  private staleCount = 0;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    setInterval(this.cleanup.bind(this), 1000 * 60 * 10);
 | 
			
		||||
  }
 | 
			
		||||
@ -245,6 +248,7 @@ class RbfCache {
 | 
			
		||||
 | 
			
		||||
  // flag a transaction as removed from the mempool
 | 
			
		||||
  public evict(txid: string, fast: boolean = false): void {
 | 
			
		||||
    this.evictionCount++;
 | 
			
		||||
    if (this.txs.has(txid) && (fast || !this.expiring.has(txid))) {
 | 
			
		||||
      const expiryTime = fast ? Date.now() + (1000 * 60 * 10) : Date.now() + (1000 * 86400); // 24 hours
 | 
			
		||||
      this.addExpiration(txid, expiryTime);
 | 
			
		||||
@ -272,18 +276,23 @@ class RbfCache {
 | 
			
		||||
        this.remove(txid);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    logger.debug(`rbf cache contains ${this.txs.size} txs, ${this.rbfTrees.size} trees, ${this.expiring.size} due to expire`);
 | 
			
		||||
    logger.debug(`rbf cache contains ${this.txs.size} txs, ${this.rbfTrees.size} trees, ${this.expiring.size} due to expire (${this.evictionCount} newly expired)`);
 | 
			
		||||
    this.evictionCount = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // remove a transaction & all previous versions from the cache
 | 
			
		||||
  private remove(txid): void {
 | 
			
		||||
    // don't remove a transaction if a newer version remains in the mempool
 | 
			
		||||
    if (!this.replacedBy.has(txid)) {
 | 
			
		||||
      const root = this.treeMap.get(txid);
 | 
			
		||||
      const replaces = this.replaces.get(txid);
 | 
			
		||||
      this.replaces.delete(txid);
 | 
			
		||||
      this.treeMap.delete(txid);
 | 
			
		||||
      this.removeTx(txid);
 | 
			
		||||
      this.removeExpiration(txid);
 | 
			
		||||
      if (root === txid) {
 | 
			
		||||
        this.removeTree(txid);
 | 
			
		||||
      }
 | 
			
		||||
      for (const tx of (replaces || [])) {
 | 
			
		||||
        // recursively remove prior versions from the cache
 | 
			
		||||
        this.replacedBy.delete(tx);
 | 
			
		||||
@ -359,18 +368,25 @@ class RbfCache {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async load({ txs, trees, expiring }): Promise<void> {
 | 
			
		||||
    txs.forEach(txEntry => {
 | 
			
		||||
      this.txs.set(txEntry.key, txEntry.value);
 | 
			
		||||
    });
 | 
			
		||||
    for (const deflatedTree of trees) {
 | 
			
		||||
      await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
 | 
			
		||||
    }
 | 
			
		||||
    expiring.forEach(expiringEntry => {
 | 
			
		||||
      if (this.txs.has(expiringEntry.key)) {
 | 
			
		||||
        this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime());
 | 
			
		||||
    try {
 | 
			
		||||
      txs.forEach(txEntry => {
 | 
			
		||||
        this.txs.set(txEntry.value.txid, txEntry.value);
 | 
			
		||||
      });
 | 
			
		||||
      this.staleCount = 0;
 | 
			
		||||
      for (const deflatedTree of trees) {
 | 
			
		||||
        await this.importTree(deflatedTree.root, deflatedTree.root, deflatedTree, this.txs);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    this.cleanup();
 | 
			
		||||
      expiring.forEach(expiringEntry => {
 | 
			
		||||
        if (this.txs.has(expiringEntry.key)) {
 | 
			
		||||
          this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime());
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`);
 | 
			
		||||
      this.staleCount = 0;
 | 
			
		||||
      this.cleanup();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      logger.err('failed to restore RBF cache: ' + (e instanceof Error ? e.message : e));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exportTree(tree: RbfTree, deflated: any = null) {
 | 
			
		||||
@ -398,6 +414,13 @@ class RbfCache {
 | 
			
		||||
    const treeInfo = deflated[txid];
 | 
			
		||||
    const replaces: RbfTree[] = [];
 | 
			
		||||
 | 
			
		||||
    // if the root tx is unknown, remove this tree and return early
 | 
			
		||||
    if (root === txid && !txs.has(txid)) {
 | 
			
		||||
      this.staleCount++;
 | 
			
		||||
      this.removeTree(deflated.key);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // check if any transactions in this tree have already been confirmed
 | 
			
		||||
    mined = mined || treeInfo.mined;
 | 
			
		||||
    let exists = mined;
 | 
			
		||||
@ -413,7 +436,7 @@ class RbfCache {
 | 
			
		||||
          this.evict(txid, true);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        // most transactions do not exist
 | 
			
		||||
        // most transactions only exist in our cache
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -219,7 +219,7 @@ class RedisCache {
 | 
			
		||||
    await memPool.$setMempool(loadedMempool);
 | 
			
		||||
    await rbfCache.load({
 | 
			
		||||
      txs: rbfTxs,
 | 
			
		||||
      trees: rbfTrees.map(loadedTree => loadedTree.value),
 | 
			
		||||
      trees: rbfTrees.map(loadedTree => { loadedTree.value.key = loadedTree.key; return loadedTree.value; }),
 | 
			
		||||
      expiring: rbfExpirations,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -577,7 +577,7 @@ class WebsocketHandler {
 | 
			
		||||
          response['utxoSpent'] = JSON.stringify(outspends);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const rbfReplacedBy = rbfCache.getReplacedBy(client['track-tx']);
 | 
			
		||||
        const rbfReplacedBy = rbfChanges.map[client['track-tx']] ? rbfCache.getReplacedBy(client['track-tx']) : false;
 | 
			
		||||
        if (rbfReplacedBy) {
 | 
			
		||||
          response['rbfTransaction'] = JSON.stringify({
 | 
			
		||||
            txid: rbfReplacedBy,
 | 
			
		||||
 | 
			
		||||
@ -78,6 +78,8 @@ interface IConfig {
 | 
			
		||||
    USERNAME: string;
 | 
			
		||||
    PASSWORD: string;
 | 
			
		||||
    TIMEOUT: number;
 | 
			
		||||
    COOKIE: boolean;
 | 
			
		||||
    COOKIE_PATH: string;
 | 
			
		||||
  };
 | 
			
		||||
  SECOND_CORE_RPC: {
 | 
			
		||||
    HOST: string;
 | 
			
		||||
@ -85,6 +87,8 @@ interface IConfig {
 | 
			
		||||
    USERNAME: string;
 | 
			
		||||
    PASSWORD: string;
 | 
			
		||||
    TIMEOUT: number;
 | 
			
		||||
    COOKIE: boolean;
 | 
			
		||||
    COOKIE_PATH: string;
 | 
			
		||||
  };
 | 
			
		||||
  DATABASE: {
 | 
			
		||||
    ENABLED: boolean;
 | 
			
		||||
@ -207,6 +211,8 @@ const defaults: IConfig = {
 | 
			
		||||
    'USERNAME': 'mempool',
 | 
			
		||||
    'PASSWORD': 'mempool',
 | 
			
		||||
    'TIMEOUT': 60000,
 | 
			
		||||
    'COOKIE': false,
 | 
			
		||||
    'COOKIE_PATH': '/bitcoin/.cookie'
 | 
			
		||||
  },
 | 
			
		||||
  'SECOND_CORE_RPC': {
 | 
			
		||||
    'HOST': '127.0.0.1',
 | 
			
		||||
@ -214,6 +220,8 @@ const defaults: IConfig = {
 | 
			
		||||
    'USERNAME': 'mempool',
 | 
			
		||||
    'PASSWORD': 'mempool',
 | 
			
		||||
    'TIMEOUT': 60000,
 | 
			
		||||
    'COOKIE': false,
 | 
			
		||||
    'COOKIE_PATH': '/bitcoin/.cookie'
 | 
			
		||||
  },
 | 
			
		||||
  'DATABASE': {
 | 
			
		||||
    'ENABLED': true,
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
var http = require('http')
 | 
			
		||||
var https = require('https')
 | 
			
		||||
import { readFileSync } from 'fs';
 | 
			
		||||
 | 
			
		||||
var JsonRPC = function (opts) {
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
@ -55,7 +56,13 @@ JsonRPC.prototype.call = function (method, params) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // use HTTP auth if user and password set
 | 
			
		||||
    if (this.opts.user && this.opts.pass) {
 | 
			
		||||
    if (this.opts.cookie) {
 | 
			
		||||
      if (!this.cachedCookie) {
 | 
			
		||||
        this.cachedCookie = readFileSync(this.opts.cookie).toString();
 | 
			
		||||
      }
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      requestOptions.auth = this.cachedCookie;
 | 
			
		||||
    } else if (this.opts.user && this.opts.pass) {
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      requestOptions.auth = this.opts.user + ':' + this.opts.pass
 | 
			
		||||
    }
 | 
			
		||||
@ -93,7 +100,7 @@ JsonRPC.prototype.call = function (method, params) {
 | 
			
		||||
      reject(err)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    request.on('response', function (response) {
 | 
			
		||||
    request.on('response', (response) => {
 | 
			
		||||
      clearTimeout(reqTimeout)
 | 
			
		||||
 | 
			
		||||
      // We need to buffer the response chunks in a nonblocking way.
 | 
			
		||||
@ -104,7 +111,7 @@ JsonRPC.prototype.call = function (method, params) {
 | 
			
		||||
      // When all the responses are finished, we decode the JSON and
 | 
			
		||||
      // depending on whether it's got a result or an error, we call
 | 
			
		||||
      // emitSuccess or emitError on the promise.
 | 
			
		||||
      response.on('end', function () {
 | 
			
		||||
      response.on('end', () => {
 | 
			
		||||
        var err
 | 
			
		||||
 | 
			
		||||
        if (cbCalled) return
 | 
			
		||||
@ -113,6 +120,14 @@ JsonRPC.prototype.call = function (method, params) {
 | 
			
		||||
        try {
 | 
			
		||||
          var decoded = JSON.parse(buffer)
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          // if we authenticated using a cookie and it failed, read the cookie file again
 | 
			
		||||
          if (
 | 
			
		||||
            response.statusCode === 401 /* Unauthorized */ &&
 | 
			
		||||
            this.opts.cookie
 | 
			
		||||
          ) {
 | 
			
		||||
            this.cachedCookie = undefined;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if (response.statusCode !== 200) {
 | 
			
		||||
            err = new Error('Invalid params, response status code: ' + response.statusCode)
 | 
			
		||||
            err.code = -32602
 | 
			
		||||
 | 
			
		||||
@ -164,7 +164,9 @@ Corresponding `docker-compose.yml` overrides:
 | 
			
		||||
    "PORT": 8332,
 | 
			
		||||
    "USERNAME": "mempool",
 | 
			
		||||
    "PASSWORD": "mempool",
 | 
			
		||||
    "TIMEOUT": 60000
 | 
			
		||||
    "TIMEOUT": 60000,
 | 
			
		||||
    "COOKIE": false,
 | 
			
		||||
    "COOKIE_PATH": ""
 | 
			
		||||
  },
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -177,6 +179,8 @@ Corresponding `docker-compose.yml` overrides:
 | 
			
		||||
      CORE_RPC_USERNAME: ""
 | 
			
		||||
      CORE_RPC_PASSWORD: ""
 | 
			
		||||
      CORE_RPC_TIMEOUT: 60000
 | 
			
		||||
      CORE_RPC_COOKIE: false
 | 
			
		||||
      CORE_RPC_COOKIE_PATH: ""
 | 
			
		||||
      ...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -231,7 +235,9 @@ Corresponding `docker-compose.yml` overrides:
 | 
			
		||||
    "PORT": 8332,
 | 
			
		||||
    "USERNAME": "mempool",
 | 
			
		||||
    "PASSWORD": "mempool",
 | 
			
		||||
    "TIMEOUT": 60000
 | 
			
		||||
    "TIMEOUT": 60000,
 | 
			
		||||
    "COOKIE": false,
 | 
			
		||||
    "COOKIE_PATH": ""
 | 
			
		||||
  },
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@ -244,6 +250,8 @@ Corresponding `docker-compose.yml` overrides:
 | 
			
		||||
      SECOND_CORE_RPC_USERNAME: ""
 | 
			
		||||
      SECOND_CORE_RPC_PASSWORD: ""
 | 
			
		||||
      SECOND_CORE_RPC_TIMEOUT: ""
 | 
			
		||||
      SECOND_CORE_RPC_COOKIE: false
 | 
			
		||||
      SECOND_CORE_RPC_COOKIE_PATH: ""
 | 
			
		||||
      ...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -41,7 +41,9 @@
 | 
			
		||||
    "PORT": __CORE_RPC_PORT__,
 | 
			
		||||
    "USERNAME": "__CORE_RPC_USERNAME__",
 | 
			
		||||
    "PASSWORD": "__CORE_RPC_PASSWORD__",
 | 
			
		||||
    "TIMEOUT": __CORE_RPC_TIMEOUT__
 | 
			
		||||
    "TIMEOUT": __CORE_RPC_TIMEOUT__,
 | 
			
		||||
    "COOKIE": __CORE_RPC_COOKIE__,
 | 
			
		||||
    "COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__"
 | 
			
		||||
  },
 | 
			
		||||
  "ELECTRUM": {
 | 
			
		||||
    "HOST": "__ELECTRUM_HOST__",
 | 
			
		||||
@ -61,7 +63,9 @@
 | 
			
		||||
    "PORT": __SECOND_CORE_RPC_PORT__,
 | 
			
		||||
    "USERNAME": "__SECOND_CORE_RPC_USERNAME__",
 | 
			
		||||
    "PASSWORD": "__SECOND_CORE_RPC_PASSWORD__",
 | 
			
		||||
    "TIMEOUT": __SECOND_CORE_RPC_TIMEOUT__
 | 
			
		||||
    "TIMEOUT": __SECOND_CORE_RPC_TIMEOUT__,
 | 
			
		||||
    "COOKIE": __SECOND_CORE_RPC_COOKIE__,
 | 
			
		||||
    "COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__"
 | 
			
		||||
  },
 | 
			
		||||
  "DATABASE": {
 | 
			
		||||
    "ENABLED": __DATABASE_ENABLED__,
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,8 @@ __CORE_RPC_PORT__=${CORE_RPC_PORT:=8332}
 | 
			
		||||
__CORE_RPC_USERNAME__=${CORE_RPC_USERNAME:=mempool}
 | 
			
		||||
__CORE_RPC_PASSWORD__=${CORE_RPC_PASSWORD:=mempool}
 | 
			
		||||
__CORE_RPC_TIMEOUT__=${CORE_RPC_TIMEOUT:=60000}
 | 
			
		||||
__CORE_RPC_COOKIE__=${CORE_RPC_COOKIE:=false}
 | 
			
		||||
__CORE_RPC_COOKIE_PATH__=${CORE_RPC_COOKIE_PATH:=""}
 | 
			
		||||
 | 
			
		||||
# ELECTRUM
 | 
			
		||||
__ELECTRUM_HOST__=${ELECTRUM_HOST:=127.0.0.1}
 | 
			
		||||
@ -63,6 +65,8 @@ __SECOND_CORE_RPC_PORT__=${SECOND_CORE_RPC_PORT:=8332}
 | 
			
		||||
__SECOND_CORE_RPC_USERNAME__=${SECOND_CORE_RPC_USERNAME:=mempool}
 | 
			
		||||
__SECOND_CORE_RPC_PASSWORD__=${SECOND_CORE_RPC_PASSWORD:=mempool}
 | 
			
		||||
__SECOND_CORE_RPC_TIMEOUT__=${SECOND_CORE_RPC_TIMEOUT:=60000}
 | 
			
		||||
__SECOND_CORE_RPC_COOKIE__=${SECOND_CORE_RPC_COOKIE:=false}
 | 
			
		||||
__SECOND_CORE_RPC_COOKIE_PATH__=${SECOND_CORE_RPC_COOKIE_PATH:=""}
 | 
			
		||||
 | 
			
		||||
# DATABASE
 | 
			
		||||
__DATABASE_ENABLED__=${DATABASE_ENABLED:=true}
 | 
			
		||||
@ -188,6 +192,8 @@ sed -i "s!__CORE_RPC_PORT__!${__CORE_RPC_PORT__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__CORE_RPC_USERNAME__!${__CORE_RPC_USERNAME__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__CORE_RPC_PASSWORD__!${__CORE_RPC_PASSWORD__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__CORE_RPC_TIMEOUT__!${__CORE_RPC_TIMEOUT__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__CORE_RPC_COOKIE__!${__CORE_RPC_COOKIE__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__CORE_RPC_COOKIE_PATH__!${__CORE_RPC_COOKIE_PATH__}!g" mempool-config.json
 | 
			
		||||
 | 
			
		||||
sed -i "s!__ELECTRUM_HOST__!${__ELECTRUM_HOST__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__ELECTRUM_PORT__!${__ELECTRUM_PORT__}!g" mempool-config.json
 | 
			
		||||
@ -205,6 +211,8 @@ sed -i "s!__SECOND_CORE_RPC_PORT__!${__SECOND_CORE_RPC_PORT__}!g" mempool-config
 | 
			
		||||
sed -i "s!__SECOND_CORE_RPC_USERNAME__!${__SECOND_CORE_RPC_USERNAME__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__SECOND_CORE_RPC_PASSWORD__!${__SECOND_CORE_RPC_PASSWORD__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__SECOND_CORE_RPC_TIMEOUT__!${__SECOND_CORE_RPC_TIMEOUT__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__SECOND_CORE_RPC_COOKIE__!${__SECOND_CORE_RPC_COOKIE__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__SECOND_CORE_RPC_COOKIE_PATH__!${__SECOND_CORE_RPC_COOKIE_PATH__}!g" mempool-config.json
 | 
			
		||||
 | 
			
		||||
sed -i "s!__DATABASE_ENABLED__!${__DATABASE_ENABLED__}!g" mempool-config.json
 | 
			
		||||
sed -i "s!__DATABASE_HOST__!${__DATABASE_HOST__}!g" mempool-config.json
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										87
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										87
									
								
								frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -33,9 +33,9 @@
 | 
			
		||||
        "clipboard": "^2.0.11",
 | 
			
		||||
        "domino": "^2.1.6",
 | 
			
		||||
        "echarts": "~5.4.3",
 | 
			
		||||
        "echarts-gl": "^2.0.9",
 | 
			
		||||
        "lightweight-charts": "~3.8.0",
 | 
			
		||||
        "ngx-echarts": "~16.0.0",
 | 
			
		||||
        "mock-socket": "~9.3.1",
 | 
			
		||||
        "ngx-echarts": "~16.2.0",
 | 
			
		||||
        "ngx-infinite-scroll": "^16.0.0",
 | 
			
		||||
        "qrcode": "1.5.1",
 | 
			
		||||
        "rxjs": "~7.8.1",
 | 
			
		||||
@ -59,10 +59,10 @@
 | 
			
		||||
      "optionalDependencies": {
 | 
			
		||||
        "@cypress/schematic": "^2.5.0",
 | 
			
		||||
        "@types/cypress": "^1.1.3",
 | 
			
		||||
        "cypress": "^13.3.0",
 | 
			
		||||
        "cypress": "^13.5.0",
 | 
			
		||||
        "cypress-fail-on-console-error": "~5.0.0",
 | 
			
		||||
        "cypress-wait-until": "^2.0.1",
 | 
			
		||||
        "mock-socket": "~9.2.1",
 | 
			
		||||
        "mock-socket": "~9.3.1",
 | 
			
		||||
        "start-server-and-test": "~2.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
@ -6429,11 +6429,6 @@
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/claygl": {
 | 
			
		||||
      "version": "1.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/clean-stack": {
 | 
			
		||||
      "version": "2.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
 | 
			
		||||
@ -7153,9 +7148,9 @@
 | 
			
		||||
      "peer": true
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/cypress": {
 | 
			
		||||
      "version": "13.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-mpI8qcTwLGiA4zEQvTC/U1xGUezVV4V8HQCOYjlEOrVmU1etVvxOjkCXHGwrlYdZU/EPmUiWfsO3yt1o+Q2bgw==",
 | 
			
		||||
      "version": "13.5.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.5.0.tgz",
 | 
			
		||||
      "integrity": "sha512-oh6U7h9w8wwHfzNDJQ6wVcAeXu31DlIYlNOBvfd6U4CcB8oe4akawQmH+QJVOMZlM42eBoCne015+svVqdwdRQ==",
 | 
			
		||||
      "hasInstallScript": true,
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
@ -7825,18 +7820,6 @@
 | 
			
		||||
        "zrender": "5.4.4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/echarts-gl": {
 | 
			
		||||
      "version": "2.0.9",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz",
 | 
			
		||||
      "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "claygl": "^1.2.1",
 | 
			
		||||
        "zrender": "^5.1.1"
 | 
			
		||||
      },
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "echarts": "^5.1.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/echarts/node_modules/tslib": {
 | 
			
		||||
      "version": "2.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
 | 
			
		||||
@ -9531,9 +9514,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/get-func-name": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
 | 
			
		||||
      "version": "2.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "*"
 | 
			
		||||
@ -12209,9 +12192,9 @@
 | 
			
		||||
      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/mock-socket": {
 | 
			
		||||
      "version": "9.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.2.1.tgz",
 | 
			
		||||
      "integrity": "sha512-aw9F9T9G2zpGipLLhSNh6ZpgUyUl4frcVmRN08uE1NWPWg43Wx6+sGPDbQ7E5iFZZDJW5b5bypMeAEHqTbIFag==",
 | 
			
		||||
      "version": "9.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz",
 | 
			
		||||
      "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 8"
 | 
			
		||||
@ -12460,9 +12443,9 @@
 | 
			
		||||
      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/ngx-echarts": {
 | 
			
		||||
      "version": "16.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-hdM7/CL29bY3sF3V5ihb7H1NeUsQlhijp8tVxT23+vkNTf9SJrUHPjs9oHOMkbTlr2Q8HB+eVpckYAL/tuK0CQ==",
 | 
			
		||||
      "version": "16.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-yhuDbp6qdkmR4kRVLS06Z0Iumod7xOj5n/Z++clRiKM24OQ4sM8WuOTicdfWy6eeYDNywdGSrri4Y5SUGRD8bg==",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "tslib": "^2.3.0"
 | 
			
		||||
      },
 | 
			
		||||
@ -21550,11 +21533,6 @@
 | 
			
		||||
        "safe-buffer": "^5.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "claygl": {
 | 
			
		||||
      "version": "1.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/claygl/-/claygl-1.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-+gGtJjT6SSHD2l2yC3MCubW/sCV40tZuSs5opdtn79vFSGUgp/lH139RNEQ6Jy078/L0aV8odCw8RSrUcMfLaQ=="
 | 
			
		||||
    },
 | 
			
		||||
    "clean-stack": {
 | 
			
		||||
      "version": "2.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
 | 
			
		||||
@ -22118,9 +22096,9 @@
 | 
			
		||||
      "peer": true
 | 
			
		||||
    },
 | 
			
		||||
    "cypress": {
 | 
			
		||||
      "version": "13.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-mpI8qcTwLGiA4zEQvTC/U1xGUezVV4V8HQCOYjlEOrVmU1etVvxOjkCXHGwrlYdZU/EPmUiWfsO3yt1o+Q2bgw==",
 | 
			
		||||
      "version": "13.5.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.5.0.tgz",
 | 
			
		||||
      "integrity": "sha512-oh6U7h9w8wwHfzNDJQ6wVcAeXu31DlIYlNOBvfd6U4CcB8oe4akawQmH+QJVOMZlM42eBoCne015+svVqdwdRQ==",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@cypress/request": "^3.0.0",
 | 
			
		||||
@ -22659,15 +22637,6 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "echarts-gl": {
 | 
			
		||||
      "version": "2.0.9",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/echarts-gl/-/echarts-gl-2.0.9.tgz",
 | 
			
		||||
      "integrity": "sha512-oKeMdkkkpJGWOzjgZUsF41DOh6cMsyrGGXimbjK2l6Xeq/dBQu4ShG2w2Dzrs/1bD27b2pLTGSaUzouY191gzA==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "claygl": "^1.2.1",
 | 
			
		||||
        "zrender": "^5.1.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "ee-first": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
 | 
			
		||||
@ -23971,9 +23940,9 @@
 | 
			
		||||
      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
 | 
			
		||||
    },
 | 
			
		||||
    "get-func-name": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
 | 
			
		||||
      "version": "2.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
 | 
			
		||||
      "optional": true
 | 
			
		||||
    },
 | 
			
		||||
    "get-intrinsic": {
 | 
			
		||||
@ -25945,9 +25914,9 @@
 | 
			
		||||
      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
 | 
			
		||||
    },
 | 
			
		||||
    "mock-socket": {
 | 
			
		||||
      "version": "9.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.2.1.tgz",
 | 
			
		||||
      "integrity": "sha512-aw9F9T9G2zpGipLLhSNh6ZpgUyUl4frcVmRN08uE1NWPWg43Wx6+sGPDbQ7E5iFZZDJW5b5bypMeAEHqTbIFag==",
 | 
			
		||||
      "version": "9.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz",
 | 
			
		||||
      "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==",
 | 
			
		||||
      "optional": true
 | 
			
		||||
    },
 | 
			
		||||
    "module-deps": {
 | 
			
		||||
@ -26141,9 +26110,9 @@
 | 
			
		||||
      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
 | 
			
		||||
    },
 | 
			
		||||
    "ngx-echarts": {
 | 
			
		||||
      "version": "16.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-hdM7/CL29bY3sF3V5ihb7H1NeUsQlhijp8tVxT23+vkNTf9SJrUHPjs9oHOMkbTlr2Q8HB+eVpckYAL/tuK0CQ==",
 | 
			
		||||
      "version": "16.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-16.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-yhuDbp6qdkmR4kRVLS06Z0Iumod7xOj5n/Z++clRiKM24OQ4sM8WuOTicdfWy6eeYDNywdGSrri4Y5SUGRD8bg==",
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "tslib": "^2.3.0"
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -86,7 +86,7 @@
 | 
			
		||||
    "domino": "^2.1.6",
 | 
			
		||||
    "echarts": "~5.4.3",
 | 
			
		||||
    "lightweight-charts": "~3.8.0",
 | 
			
		||||
    "ngx-echarts": "~16.0.0",
 | 
			
		||||
    "ngx-echarts": "~16.2.0",
 | 
			
		||||
    "ngx-infinite-scroll": "^16.0.0",
 | 
			
		||||
    "qrcode": "1.5.1",
 | 
			
		||||
    "rxjs": "~7.8.1",
 | 
			
		||||
@ -110,10 +110,10 @@
 | 
			
		||||
  "optionalDependencies": {
 | 
			
		||||
    "@cypress/schematic": "^2.5.0",
 | 
			
		||||
    "@types/cypress": "^1.1.3",
 | 
			
		||||
    "cypress": "^13.3.0",
 | 
			
		||||
    "cypress": "^13.5.0",
 | 
			
		||||
    "cypress-fail-on-console-error": "~5.0.0",
 | 
			
		||||
    "cypress-wait-until": "^2.0.1",
 | 
			
		||||
    "mock-socket": "~9.2.1",
 | 
			
		||||
    "mock-socket": "~9.3.1",
 | 
			
		||||
    "start-server-and-test": "~2.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "scarfSettings": {
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,10 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { AppPreloadingStrategy } from './app.preloading-strategy'
 | 
			
		||||
import { StartComponent } from './components/start/start.component';
 | 
			
		||||
import { TransactionComponent } from './components/transaction/transaction.component';
 | 
			
		||||
import { BlockComponent } from './components/block/block.component';
 | 
			
		||||
import { BlockViewComponent } from './components/block-view/block-view.component';
 | 
			
		||||
import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component';
 | 
			
		||||
import { ClockComponent } from './components/clock/clock.component';
 | 
			
		||||
import { AddressComponent } from './components/address/address.component';
 | 
			
		||||
import { MasterPageComponent } from './components/master-page/master-page.component';
 | 
			
		||||
import { AboutComponent } from './components/about/about.component';
 | 
			
		||||
import { StatusViewComponent } from './components/status-view/status-view.component';
 | 
			
		||||
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
 | 
			
		||||
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
 | 
			
		||||
import { TrademarkPolicyComponent } from './components/trademark-policy/trademark-policy.component';
 | 
			
		||||
import { BisqMasterPageComponent } from './components/bisq-master-page/bisq-master-page.component';
 | 
			
		||||
import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
 | 
			
		||||
import { BlocksList } from './components/blocks-list/blocks-list.component';
 | 
			
		||||
import { RbfList } from './components/rbf-list/rbf-list.component';
 | 
			
		||||
import { LiquidMasterPageComponent } from './components/liquid-master-page/liquid-master-page.component';
 | 
			
		||||
import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component';
 | 
			
		||||
import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component';
 | 
			
		||||
import { AssetsComponent } from './components/assets/assets.component';
 | 
			
		||||
import { AssetComponent } from './components/asset/asset.component';
 | 
			
		||||
import { AssetsNavComponent } from './components/assets/assets-nav/assets-nav.component';
 | 
			
		||||
import { CalculatorComponent } from './components/calculator/calculator.component';
 | 
			
		||||
 | 
			
		||||
const browserWindow = window || {};
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
@ -37,95 +17,13 @@ let routes: Routes = [
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        pathMatch: 'full',
 | 
			
		||||
        loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule),
 | 
			
		||||
        loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: MasterPageComponent,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            path: 'mining/blocks',
 | 
			
		||||
            redirectTo: 'blocks',
 | 
			
		||||
            pathMatch: 'full'
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'tx/push',
 | 
			
		||||
            component: PushTransactionComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'about',
 | 
			
		||||
            component: AboutComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'blocks',
 | 
			
		||||
            component: BlocksList,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'rbf',
 | 
			
		||||
            component: RbfList,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'terms-of-service',
 | 
			
		||||
            component: TermsOfServiceComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'privacy-policy',
 | 
			
		||||
            component: PrivacyPolicyComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'trademark-policy',
 | 
			
		||||
            component: TrademarkPolicyComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'address/:id',
 | 
			
		||||
            children: [],
 | 
			
		||||
            component: AddressComponent,
 | 
			
		||||
            data: {
 | 
			
		||||
              ogImage: true,
 | 
			
		||||
              networkSpecific: true,
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'tx',
 | 
			
		||||
            component: StartComponent,
 | 
			
		||||
            data: { networkSpecific: true },
 | 
			
		||||
            children: [
 | 
			
		||||
              {
 | 
			
		||||
                path: ':id',
 | 
			
		||||
                component: TransactionComponent
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'block',
 | 
			
		||||
            component: StartComponent,
 | 
			
		||||
            data: { networkSpecific: true },
 | 
			
		||||
              children: [
 | 
			
		||||
              {
 | 
			
		||||
                path: ':id',
 | 
			
		||||
                component: BlockComponent,
 | 
			
		||||
                data: {
 | 
			
		||||
                  ogImage: true
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'docs',
 | 
			
		||||
            loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule),
 | 
			
		||||
            data: { preload: true },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'api',
 | 
			
		||||
            loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning',
 | 
			
		||||
            loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule),
 | 
			
		||||
            data: { preload: browserWindowEnv && browserWindowEnv.LIGHTNING === true, networks: ['bitcoin'] },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'status',
 | 
			
		||||
@ -134,7 +32,8 @@ let routes: Routes = [
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
        loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '**',
 | 
			
		||||
@ -153,88 +52,13 @@ let routes: Routes = [
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        pathMatch: 'full',
 | 
			
		||||
        loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
        loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: MasterPageComponent,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            path: 'tx/push',
 | 
			
		||||
            component: PushTransactionComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'about',
 | 
			
		||||
            component: AboutComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'blocks',
 | 
			
		||||
            component: BlocksList,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'rbf',
 | 
			
		||||
            component: RbfList,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'terms-of-service',
 | 
			
		||||
            component: TermsOfServiceComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'privacy-policy',
 | 
			
		||||
            component: PrivacyPolicyComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'trademark-policy',
 | 
			
		||||
            component: TrademarkPolicyComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'address/:id',
 | 
			
		||||
            children: [],
 | 
			
		||||
            component: AddressComponent,
 | 
			
		||||
            data: {
 | 
			
		||||
              ogImage: true,
 | 
			
		||||
              networkSpecific: true,
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'tx',
 | 
			
		||||
            data: { networkSpecific: true },
 | 
			
		||||
            component: StartComponent,
 | 
			
		||||
            children: [
 | 
			
		||||
              {
 | 
			
		||||
                path: ':id',
 | 
			
		||||
                component: TransactionComponent
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'block',
 | 
			
		||||
            data: { networkSpecific: true },
 | 
			
		||||
            component: StartComponent,
 | 
			
		||||
            children: [
 | 
			
		||||
              {
 | 
			
		||||
                path: ':id',
 | 
			
		||||
                component: BlockComponent,
 | 
			
		||||
                data: {
 | 
			
		||||
                  ogImage: true
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'docs',
 | 
			
		||||
            loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'api',
 | 
			
		||||
            loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
        loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'status',
 | 
			
		||||
@ -243,7 +67,8 @@ let routes: Routes = [
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
        loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '**',
 | 
			
		||||
@ -254,97 +79,13 @@ let routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    pathMatch: 'full',
 | 
			
		||||
    loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
    loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
 | 
			
		||||
    data: { preload: true },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: MasterPageComponent,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        path: 'mining/blocks',
 | 
			
		||||
        redirectTo: 'blocks',
 | 
			
		||||
        pathMatch: 'full'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx/push',
 | 
			
		||||
        component: PushTransactionComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'about',
 | 
			
		||||
        component: AboutComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'blocks',
 | 
			
		||||
        component: BlocksList,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'rbf',
 | 
			
		||||
        component: RbfList,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tools/calculator',
 | 
			
		||||
        component: CalculatorComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'terms-of-service',
 | 
			
		||||
        component: TermsOfServiceComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'privacy-policy',
 | 
			
		||||
        component: PrivacyPolicyComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'trademark-policy',
 | 
			
		||||
        component: TrademarkPolicyComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'address/:id',
 | 
			
		||||
        children: [],
 | 
			
		||||
        component: AddressComponent,
 | 
			
		||||
        data: {
 | 
			
		||||
          ogImage: true,
 | 
			
		||||
          networkSpecific: true,
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx',
 | 
			
		||||
        data: { networkSpecific: true },
 | 
			
		||||
        component: StartComponent,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            path: ':id',
 | 
			
		||||
            component: TransactionComponent
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'block',
 | 
			
		||||
        data: { networkSpecific: true },
 | 
			
		||||
        component: StartComponent,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            path: ':id',
 | 
			
		||||
            component: BlockComponent,
 | 
			
		||||
            data: {
 | 
			
		||||
              ogImage: true
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'docs',
 | 
			
		||||
        loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'api',
 | 
			
		||||
        loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'lightning',
 | 
			
		||||
        data: { networks: ['bitcoin'] },
 | 
			
		||||
        loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule)
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule),
 | 
			
		||||
    data: { preload: true },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: 'preview',
 | 
			
		||||
@ -390,7 +131,8 @@ let routes: Routes = [
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
    loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule),
 | 
			
		||||
    data: { preload: true },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: '**',
 | 
			
		||||
@ -401,7 +143,6 @@ let routes: Routes = [
 | 
			
		||||
if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'bisq') {
 | 
			
		||||
  routes = [{
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: BisqMasterPageComponent,
 | 
			
		||||
    loadChildren: () => import('./bisq/bisq.module').then(m => m.BisqModule)
 | 
			
		||||
  }];
 | 
			
		||||
}
 | 
			
		||||
@ -414,105 +155,13 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
 | 
			
		||||
        {
 | 
			
		||||
          path: '',
 | 
			
		||||
          pathMatch: 'full',
 | 
			
		||||
          loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
          loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
 | 
			
		||||
          data: { preload: true },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '',
 | 
			
		||||
          component: LiquidMasterPageComponent,
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              path: 'tx/push',
 | 
			
		||||
              component: PushTransactionComponent,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'about',
 | 
			
		||||
              component: AboutComponent,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'blocks',
 | 
			
		||||
              component: BlocksList,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'terms-of-service',
 | 
			
		||||
              component: TermsOfServiceComponent
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'privacy-policy',
 | 
			
		||||
              component: PrivacyPolicyComponent
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'trademark-policy',
 | 
			
		||||
              component: TrademarkPolicyComponent
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'address/:id',
 | 
			
		||||
              children: [],
 | 
			
		||||
              component: AddressComponent,
 | 
			
		||||
              data: {
 | 
			
		||||
                ogImage: true,
 | 
			
		||||
                networkSpecific: true,
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'tx',
 | 
			
		||||
              data: { networkSpecific: true },
 | 
			
		||||
              component: StartComponent,
 | 
			
		||||
              children: [
 | 
			
		||||
                {
 | 
			
		||||
                  path: ':id',
 | 
			
		||||
                  component: TransactionComponent
 | 
			
		||||
                },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'block',
 | 
			
		||||
              data: { networkSpecific: true },
 | 
			
		||||
              component: StartComponent,
 | 
			
		||||
              children: [
 | 
			
		||||
                {
 | 
			
		||||
                  path: ':id',
 | 
			
		||||
                  component: BlockComponent,
 | 
			
		||||
                  data: {
 | 
			
		||||
                    ogImage: true
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
              ],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'assets',
 | 
			
		||||
              data: { networks: ['liquid'] },
 | 
			
		||||
              component: AssetsNavComponent,
 | 
			
		||||
              children: [
 | 
			
		||||
                {
 | 
			
		||||
                  path: 'all',
 | 
			
		||||
                  data: { networks: ['liquid'] },
 | 
			
		||||
                  component: AssetsComponent,
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  path: 'asset/:id',
 | 
			
		||||
                  data: { networkSpecific: true },
 | 
			
		||||
                  component: AssetComponent
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  path: 'group/:id',
 | 
			
		||||
                  data: { networkSpecific: true },
 | 
			
		||||
                  component: AssetGroupComponent
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  path: '**',
 | 
			
		||||
                  redirectTo: 'all'
 | 
			
		||||
                }
 | 
			
		||||
              ]
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'docs',
 | 
			
		||||
              loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'api',
 | 
			
		||||
              loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
          loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule),
 | 
			
		||||
          data: { preload: true },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'status',
 | 
			
		||||
@ -521,7 +170,8 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '',
 | 
			
		||||
          loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
          loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
 | 
			
		||||
          data: { preload: true },
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: '**',
 | 
			
		||||
@ -532,110 +182,13 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
 | 
			
		||||
    {
 | 
			
		||||
      path: '',
 | 
			
		||||
      pathMatch: 'full',
 | 
			
		||||
      loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
      loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
 | 
			
		||||
      data: { preload: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '',
 | 
			
		||||
      component: LiquidMasterPageComponent,
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          path: 'tx/push',
 | 
			
		||||
          component: PushTransactionComponent,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'about',
 | 
			
		||||
          component: AboutComponent,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'blocks',
 | 
			
		||||
          component: BlocksList,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'terms-of-service',
 | 
			
		||||
          component: TermsOfServiceComponent
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'privacy-policy',
 | 
			
		||||
          component: PrivacyPolicyComponent
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'trademark-policy',
 | 
			
		||||
          component: TrademarkPolicyComponent
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'address/:id',
 | 
			
		||||
          children: [],
 | 
			
		||||
          component: AddressComponent,
 | 
			
		||||
          data: {
 | 
			
		||||
            ogImage: true,
 | 
			
		||||
            networkSpecific: true,
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'tx',
 | 
			
		||||
          data: { networkSpecific: true },
 | 
			
		||||
          component: StartComponent,
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              path: ':id',
 | 
			
		||||
              component: TransactionComponent
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'block',
 | 
			
		||||
          data: { networkSpecific: true },
 | 
			
		||||
          component: StartComponent,
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              path: ':id',
 | 
			
		||||
              component: BlockComponent,
 | 
			
		||||
              data: {
 | 
			
		||||
                ogImage: true
 | 
			
		||||
              }
 | 
			
		||||
            },
 | 
			
		||||
          ],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'assets',
 | 
			
		||||
          data: { networks: ['liquid'] },
 | 
			
		||||
          component: AssetsNavComponent,
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              path: 'featured',
 | 
			
		||||
              data: { networkSpecific: true },
 | 
			
		||||
              component: AssetsFeaturedComponent,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'all',
 | 
			
		||||
              data: { networks: ['liquid'] },
 | 
			
		||||
              component: AssetsComponent,
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'asset/:id',
 | 
			
		||||
              data: { networkSpecific: true },
 | 
			
		||||
              component: AssetComponent
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: 'group/:id',
 | 
			
		||||
              data: { networkSpecific: true },
 | 
			
		||||
              component: AssetGroupComponent
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              path: '**',
 | 
			
		||||
              redirectTo: 'featured'
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'docs',
 | 
			
		||||
          loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          path: 'api',
 | 
			
		||||
          loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
      loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule),
 | 
			
		||||
      data: { preload: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'preview',
 | 
			
		||||
@ -657,7 +210,8 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '',
 | 
			
		||||
      loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule)
 | 
			
		||||
      loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule),
 | 
			
		||||
      data: { preload: true },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '**',
 | 
			
		||||
 | 
			
		||||
@ -27,9 +27,11 @@ import { AutofocusDirective } from '../components/ngx-bootstrap-multiselect/auto
 | 
			
		||||
import { MultiSelectSearchFilter } from '../components/ngx-bootstrap-multiselect/search-filter.pipe';
 | 
			
		||||
import { OffClickDirective } from '../components/ngx-bootstrap-multiselect/off-click.directive';
 | 
			
		||||
import { NgxDropdownMultiselectComponent } from '../components/ngx-bootstrap-multiselect/ngx-bootstrap-multiselect.component';
 | 
			
		||||
import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
    BisqMasterPageComponent,
 | 
			
		||||
    BisqTransactionsComponent,
 | 
			
		||||
    BisqTransactionComponent,
 | 
			
		||||
    BisqBlockComponent,
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { AboutComponent } from '../components/about/about.component';
 | 
			
		||||
import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
 | 
			
		||||
import { BisqTransactionsComponent } from './bisq-transactions/bisq-transactions.component';
 | 
			
		||||
import { BisqTransactionComponent } from './bisq-transaction/bisq-transaction.component';
 | 
			
		||||
import { BisqBlockComponent } from './bisq-block/bisq-block.component';
 | 
			
		||||
@ -10,78 +10,83 @@ import { BisqStatsComponent } from './bisq-stats/bisq-stats.component';
 | 
			
		||||
import { BisqDashboardComponent } from './bisq-dashboard/bisq-dashboard.component';
 | 
			
		||||
import { BisqMarketComponent } from './bisq-market/bisq-market.component';
 | 
			
		||||
import { BisqMainDashboardComponent } from './bisq-main-dashboard/bisq-main-dashboard.component';
 | 
			
		||||
import { TermsOfServiceComponent } from '../components/terms-of-service/terms-of-service.component';
 | 
			
		||||
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
      path: '',
 | 
			
		||||
      component: BisqMainDashboardComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'markets',
 | 
			
		||||
      data: { networks: ['bisq'] },
 | 
			
		||||
      component: BisqDashboardComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'transactions',
 | 
			
		||||
      data: { networks: ['bisq'] },
 | 
			
		||||
      component: BisqTransactionsComponent
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'market/:pair',
 | 
			
		||||
      data: { networkSpecific: true },
 | 
			
		||||
      component: BisqMarketComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'tx/push',
 | 
			
		||||
      component: PushTransactionComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'tx/:id',
 | 
			
		||||
      data: { networkSpecific: true },
 | 
			
		||||
      component: BisqTransactionComponent
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'blocks',
 | 
			
		||||
      children: [],
 | 
			
		||||
      component: BisqBlocksComponent
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'block/:id',
 | 
			
		||||
      data: { networkSpecific: true },
 | 
			
		||||
      component: BisqBlockComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'address/:id',
 | 
			
		||||
      data: { networkSpecific: true },
 | 
			
		||||
      component: BisqAddressComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'stats',
 | 
			
		||||
      data: { networks: ['bisq'] },
 | 
			
		||||
      component: BisqStatsComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'about',
 | 
			
		||||
      component: AboutComponent,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'docs',
 | 
			
		||||
      loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'api',
 | 
			
		||||
      loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: 'terms-of-service',
 | 
			
		||||
      component: TermsOfServiceComponent
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: '**',
 | 
			
		||||
      redirectTo: ''
 | 
			
		||||
    }
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: BisqMasterPageComponent,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        path: '',
 | 
			
		||||
        component: BisqMainDashboardComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'markets',
 | 
			
		||||
        data: { networks: ['bisq'] },
 | 
			
		||||
        component: BisqDashboardComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'transactions',
 | 
			
		||||
        data: { networks: ['bisq'] },
 | 
			
		||||
        component: BisqTransactionsComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'market/:pair',
 | 
			
		||||
        data: { networkSpecific: true },
 | 
			
		||||
        component: BisqMarketComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx/push',
 | 
			
		||||
        component: PushTransactionComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx/:id',
 | 
			
		||||
        data: { networkSpecific: true },
 | 
			
		||||
        component: BisqTransactionComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'blocks',
 | 
			
		||||
        children: [],
 | 
			
		||||
        component: BisqBlocksComponent
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'block/:id',
 | 
			
		||||
        data: { networkSpecific: true },
 | 
			
		||||
        component: BisqBlockComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'address/:id',
 | 
			
		||||
        data: { networkSpecific: true },
 | 
			
		||||
        component: BisqAddressComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'stats',
 | 
			
		||||
        data: { networks: ['bisq'] },
 | 
			
		||||
        component: BisqStatsComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'about',
 | 
			
		||||
        loadChildren: () => import('../components/about/about.module').then(m => m.AboutModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'docs',
 | 
			
		||||
        loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'api',
 | 
			
		||||
        loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'terms-of-service',
 | 
			
		||||
        loadChildren: () => import('../components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: '**',
 | 
			
		||||
        redirectTo: ''
 | 
			
		||||
      }
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								frontend/src/app/bitcoin-graphs.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/app/bitcoin-graphs.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { MasterPageComponent } from './components/master-page/master-page.component';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: MasterPageComponent,
 | 
			
		||||
    loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule),
 | 
			
		||||
    data: { preload: true },
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class BitcoinGraphsRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    BitcoinGraphsRoutingModule,
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class BitcoinGraphsModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								frontend/src/app/components/about/about.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								frontend/src/app/components/about/about.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { AboutComponent } from './about.component';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: AboutComponent,
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class AboutRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    AboutRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    AboutComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class AboutModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								frontend/src/app/components/block/block.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								frontend/src/app/components/block/block.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { BlockComponent } from './block.component';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: ':id',
 | 
			
		||||
    component: BlockComponent,
 | 
			
		||||
    data: {
 | 
			
		||||
      ogImage: true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class BlockRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    BlockRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    BlockComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class BlockModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,3 @@
 | 
			
		||||
.fee-distribution-chart {
 | 
			
		||||
  margin-top: 0.75rem;
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { OnChanges, OnDestroy } from '@angular/core';
 | 
			
		||||
import { HostListener, OnChanges, OnDestroy } from '@angular/core';
 | 
			
		||||
import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core';
 | 
			
		||||
import { TransactionStripped } from '../../interfaces/websocket.interface';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
@ -9,6 +9,7 @@ import { Subscription } from 'rxjs';
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-fee-distribution-graph',
 | 
			
		||||
  templateUrl: './fee-distribution-graph.component.html',
 | 
			
		||||
  styleUrls: ['./fee-distribution-graph.component.scss'],
 | 
			
		||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
			
		||||
})
 | 
			
		||||
export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
@ -25,6 +26,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
 | 
			
		||||
  simple: boolean = false;
 | 
			
		||||
  data: number[][];
 | 
			
		||||
  labelInterval: number = 50;
 | 
			
		||||
  smallScreen: boolean = window.innerWidth < 450;
 | 
			
		||||
 | 
			
		||||
  rateUnitSub: Subscription;
 | 
			
		||||
  weightMode: boolean = false;
 | 
			
		||||
@ -95,9 +97,9 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
 | 
			
		||||
    this.mempoolVsizeFeesOptions = {
 | 
			
		||||
      grid: {
 | 
			
		||||
        height: '210',
 | 
			
		||||
        right: '20',
 | 
			
		||||
        right: this.smallScreen ? '10' : '20',
 | 
			
		||||
        top: '22',
 | 
			
		||||
        left: '40',
 | 
			
		||||
        left: this.smallScreen ? '10' : '40',
 | 
			
		||||
      },
 | 
			
		||||
      xAxis: {
 | 
			
		||||
        type: 'category',
 | 
			
		||||
@ -131,16 +133,17 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        axisLabel: {
 | 
			
		||||
          show: true,
 | 
			
		||||
          show: !this.smallScreen,
 | 
			
		||||
          formatter: (value: number): string => {
 | 
			
		||||
            const unitValue = this.weightMode ? value / 4 : value;
 | 
			
		||||
            const selectedPowerOfTen = selectPowerOfTen(unitValue);
 | 
			
		||||
            const newVal = Math.round(unitValue / selectedPowerOfTen.divider);
 | 
			
		||||
            const scaledValue = unitValue / selectedPowerOfTen.divider;
 | 
			
		||||
            const newVal = scaledValue >= 100 ? Math.round(scaledValue) : scaledValue.toPrecision(3);
 | 
			
		||||
            return `${newVal}${selectedPowerOfTen.unit}`;
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        axisTick: {
 | 
			
		||||
          show: true,
 | 
			
		||||
          show: !this.smallScreen,
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      series: [{
 | 
			
		||||
@ -151,11 +154,13 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
 | 
			
		||||
          position: 'top',
 | 
			
		||||
          color: '#ffffff',
 | 
			
		||||
          textShadowBlur: 0,
 | 
			
		||||
          fontSize: this.smallScreen ? 10 : 12,
 | 
			
		||||
          formatter: (label: { data: number[] }): string => {
 | 
			
		||||
            const value = label.data[1];
 | 
			
		||||
            const unitValue = this.weightMode ? value / 4 : value;
 | 
			
		||||
            const selectedPowerOfTen = selectPowerOfTen(unitValue);
 | 
			
		||||
            const newVal = Math.round(unitValue / selectedPowerOfTen.divider);
 | 
			
		||||
            const scaledValue = unitValue / selectedPowerOfTen.divider;
 | 
			
		||||
            const newVal = scaledValue >= 100 ? Math.round(scaledValue) : scaledValue.toPrecision(3);
 | 
			
		||||
            return `${newVal}${selectedPowerOfTen.unit}`;
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
@ -179,6 +184,16 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @HostListener('window:resize', ['$event'])
 | 
			
		||||
  onResize(): void {
 | 
			
		||||
    const isSmallScreen = window.innerWidth < 450;
 | 
			
		||||
    if (this.smallScreen !== isSmallScreen) {
 | 
			
		||||
      this.smallScreen = isSmallScreen;
 | 
			
		||||
      this.prepareChart();
 | 
			
		||||
      this.mountChart();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnDestroy(): void {
 | 
			
		||||
    this.rateUnitSub.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { PrivacyPolicyComponent } from './privacy-policy.component';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: PrivacyPolicyComponent,
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class PrivacyPolicyRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    PrivacyPolicyRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    PrivacyPolicyComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class PrivacyPolicyModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { TermsOfServiceComponent } from './terms-of-service.component';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: TermsOfServiceComponent,
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TermsModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    TermsModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    TermsOfServiceComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TermsOfServiceModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { TrademarkPolicyComponent } from './trademark-policy.component';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: TrademarkPolicyComponent,
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TrademarkRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    TrademarkRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    TrademarkPolicyComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TrademarkModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -422,6 +422,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
			
		||||
      }
 | 
			
		||||
      this.rbfTransaction = rbfTransaction;
 | 
			
		||||
      this.replaced = true;
 | 
			
		||||
      this.stateService.markBlock$.next({});
 | 
			
		||||
 | 
			
		||||
      if (rbfTransaction && !this.tx) {
 | 
			
		||||
        this.fetchCachedTx$.next(this.txId);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,45 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { TransactionComponent } from './transaction.component';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
import { TxBowtieModule } from '../tx-bowtie-graph/tx-bowtie.module';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: ':id',
 | 
			
		||||
    component: TransactionComponent,
 | 
			
		||||
    data: {
 | 
			
		||||
      ogImage: true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TransactionRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    TransactionRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
    TxBowtieModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    TransactionComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TransactionModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ import { Outspend, Transaction, Vin, Vout } from '../../interfaces/electrs.inter
 | 
			
		||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
import { environment } from '../../../environments/environment';
 | 
			
		||||
import { AssetsService } from '../../services/assets.service';
 | 
			
		||||
import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators';
 | 
			
		||||
import { filter, map, tap, switchMap, shareReplay, catchError } from 'rxjs/operators';
 | 
			
		||||
import { BlockExtended } from '../../interfaces/node-api.interface';
 | 
			
		||||
import { ApiService } from '../../services/api.service';
 | 
			
		||||
import { PriceService } from '../../services/price.service';
 | 
			
		||||
@ -75,7 +75,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
              for (let i = 0; i < txIds.length; i += 50) {
 | 
			
		||||
                batches.push(txIds.slice(i, i + 50));
 | 
			
		||||
              }
 | 
			
		||||
              return forkJoin(batches.map(batch => this.apiService.getOutspendsBatched$(batch)));
 | 
			
		||||
              return forkJoin(batches.map(batch => { return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 250, batch); }));
 | 
			
		||||
            } else {
 | 
			
		||||
              return of([]);
 | 
			
		||||
            }
 | 
			
		||||
@ -90,6 +90,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
            outspends.forEach((outspend, i) => {
 | 
			
		||||
              transactions[i]._outspends = outspend;
 | 
			
		||||
            });
 | 
			
		||||
            this.ref.markForCheck();
 | 
			
		||||
          }),
 | 
			
		||||
        ),
 | 
			
		||||
      this.stateService.utxoSpent$
 | 
			
		||||
@ -108,6 +109,10 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
          .pipe(
 | 
			
		||||
            filter(() => this.stateService.env.LIGHTNING),
 | 
			
		||||
            switchMap((txIds) => this.apiService.getChannelByTxIds$(txIds)),
 | 
			
		||||
            catchError((error) => {
 | 
			
		||||
              // handle 404
 | 
			
		||||
              return of([]);
 | 
			
		||||
            }),
 | 
			
		||||
            tap((channels) => {
 | 
			
		||||
              if (!this.transactions) {
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
@ -123,7 +123,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges {
 | 
			
		||||
        .pipe(
 | 
			
		||||
          switchMap((txid) => {
 | 
			
		||||
            if (!this.cached) {
 | 
			
		||||
              return this.apiService.getOutspendsBatched$([txid]);
 | 
			
		||||
              return this.apiService.cachedRequest(this.apiService.getOutspendsBatched$, 250, [txid]);
 | 
			
		||||
            } else {
 | 
			
		||||
              return of(null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { SharedModule } from '../../shared/shared.module';
 | 
			
		||||
import { TxBowtieGraphComponent } from '../tx-bowtie-graph/tx-bowtie-graph.component';
 | 
			
		||||
import { TxBowtieGraphTooltipComponent } from '../tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    TxBowtieGraphComponent,
 | 
			
		||||
    TxBowtieGraphTooltipComponent,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    TxBowtieGraphComponent,
 | 
			
		||||
    TxBowtieGraphTooltipComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class TxBowtieModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,8 +8,6 @@ import { BlockSizesWeightsGraphComponent } from '../components/block-sizes-weigh
 | 
			
		||||
import { GraphsComponent } from '../components/graphs/graphs.component';
 | 
			
		||||
import { HashrateChartComponent } from '../components/hashrate-chart/hashrate-chart.component';
 | 
			
		||||
import { HashrateChartPoolsComponent } from '../components/hashrates-chart-pools/hashrate-chart-pools.component';
 | 
			
		||||
import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
 | 
			
		||||
import { MasterPageComponent } from '../components/master-page/master-page.component';
 | 
			
		||||
import { MempoolBlockComponent } from '../components/mempool-block/mempool-block.component';
 | 
			
		||||
import { MiningDashboardComponent } from '../components/mining-dashboard/mining-dashboard.component';
 | 
			
		||||
import { PoolRankingComponent } from '../components/pool-ranking/pool-ranking.component';
 | 
			
		||||
@ -18,22 +16,10 @@ import { StartComponent } from '../components/start/start.component';
 | 
			
		||||
import { StatisticsComponent } from '../components/statistics/statistics.component';
 | 
			
		||||
import { TelevisionComponent } from '../components/television/television.component';
 | 
			
		||||
import { DashboardComponent } from '../dashboard/dashboard.component';
 | 
			
		||||
import { NodesNetworksChartComponent } from '../lightning/nodes-networks-chart/nodes-networks-chart.component';
 | 
			
		||||
import { LightningStatisticsChartComponent } from '../lightning/statistics-chart/lightning-statistics-chart.component';
 | 
			
		||||
import { NodesPerISPChartComponent } from '../lightning/nodes-per-isp-chart/nodes-per-isp-chart.component';
 | 
			
		||||
import { NodesPerCountryChartComponent } from '../lightning/nodes-per-country-chart/nodes-per-country-chart.component';
 | 
			
		||||
import { NodesMap } from '../lightning/nodes-map/nodes-map.component';
 | 
			
		||||
import { NodesChannelsMap } from '../lightning/nodes-channels-map/nodes-channels-map.component';
 | 
			
		||||
 | 
			
		||||
const browserWindow = window || {};
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
const browserWindowEnv = browserWindow.__env || {};
 | 
			
		||||
const isLiquid = browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: isLiquid ? LiquidMasterPageComponent : MasterPageComponent,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        path: 'mining/pool/:slug',
 | 
			
		||||
@ -108,34 +94,9 @@ const routes: Routes = [
 | 
			
		||||
            component: BlockSizesWeightsGraphComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning/nodes-networks',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            component: NodesNetworksChartComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning/capacity',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            component: LightningStatisticsChartComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning/nodes-per-isp',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            component: NodesPerISPChartComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning/nodes-per-country',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            component: NodesPerCountryChartComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning/nodes-map',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            component: NodesMap,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'lightning/nodes-channels-map',
 | 
			
		||||
            data: { networks: ['bitcoin'] },
 | 
			
		||||
            component: NodesChannelsMap,
 | 
			
		||||
            path: 'lightning',
 | 
			
		||||
            data: { preload: true, networks: ['bitcoin'] },
 | 
			
		||||
            loadChildren: () => import ('./lightning-graphs.module').then(m => m.LightningGraphsModule),
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: '',
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								frontend/src/app/graphs/lightning-graphs.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								frontend/src/app/graphs/lightning-graphs.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { SharedModule } from '../shared/shared.module';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { NodesNetworksChartComponent } from '../lightning/nodes-networks-chart/nodes-networks-chart.component';
 | 
			
		||||
import { LightningStatisticsChartComponent } from '../lightning/statistics-chart/lightning-statistics-chart.component';
 | 
			
		||||
import { NodesPerISPChartComponent } from '../lightning/nodes-per-isp-chart/nodes-per-isp-chart.component';
 | 
			
		||||
import { NodesPerCountryChartComponent } from '../lightning/nodes-per-country-chart/nodes-per-country-chart.component';
 | 
			
		||||
import { NodesMap } from '../lightning/nodes-map/nodes-map.component';
 | 
			
		||||
import { NodesChannelsMap } from '../lightning/nodes-channels-map/nodes-channels-map.component';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: 'nodes-networks',
 | 
			
		||||
    data: { networks: ['bitcoin'] },
 | 
			
		||||
    component: NodesNetworksChartComponent,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: 'capacity',
 | 
			
		||||
    data: { networks: ['bitcoin'] },
 | 
			
		||||
    component: LightningStatisticsChartComponent,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: 'nodes-per-isp',
 | 
			
		||||
    data: { networks: ['bitcoin'] },
 | 
			
		||||
    component: NodesPerISPChartComponent,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: 'nodes-per-country',
 | 
			
		||||
    data: { networks: ['bitcoin'] },
 | 
			
		||||
    component: NodesPerCountryChartComponent,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: 'nodes-map',
 | 
			
		||||
    data: { networks: ['bitcoin'] },
 | 
			
		||||
    component: NodesMap,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    path: 'nodes-channels-map',
 | 
			
		||||
    data: { networks: ['bitcoin'] },
 | 
			
		||||
    component: NodesChannelsMap,
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [RouterModule.forChild(routes)],
 | 
			
		||||
  exports: [RouterModule],
 | 
			
		||||
})
 | 
			
		||||
export class LightningGraphsRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
    LightningGraphsRoutingModule,
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class LightningGraphsModule { }
 | 
			
		||||
							
								
								
									
										37
									
								
								frontend/src/app/liquid/liquid-graphs.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/src/app/liquid/liquid-graphs.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: LiquidMasterPageComponent,
 | 
			
		||||
    loadChildren: () => import('../graphs/graphs.module').then(m => m.GraphsModule),
 | 
			
		||||
    data: { preload: true },
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class LiquidGraphsRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    LiquidGraphsRoutingModule,
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class LiquidGraphsModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										125
									
								
								frontend/src/app/liquid/liquid-master-page.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								frontend/src/app/liquid/liquid-master-page.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { SharedModule } from '../shared/shared.module';
 | 
			
		||||
import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
 | 
			
		||||
 | 
			
		||||
import { StartComponent } from '../components/start/start.component';
 | 
			
		||||
import { AddressComponent } from '../components/address/address.component';
 | 
			
		||||
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
 | 
			
		||||
import { BlocksList } from '../components/blocks-list/blocks-list.component';
 | 
			
		||||
import { AssetGroupComponent } from '../components/assets/asset-group/asset-group.component';
 | 
			
		||||
import { AssetsComponent } from '../components/assets/assets.component';
 | 
			
		||||
import { AssetComponent } from '../components/asset/asset.component';
 | 
			
		||||
import { AssetsNavComponent } from '../components/assets/assets-nav/assets-nav.component';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: LiquidMasterPageComponent,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx/push',
 | 
			
		||||
        component: PushTransactionComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'about',
 | 
			
		||||
        loadChildren: () => import('../components/about/about.module').then(m => m.AboutModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'blocks',
 | 
			
		||||
        component: BlocksList,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'terms-of-service',
 | 
			
		||||
        loadChildren: () => import('../components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'privacy-policy',
 | 
			
		||||
        loadChildren: () => import('../components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'trademark-policy',
 | 
			
		||||
        loadChildren: () => import('../components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'address/:id',
 | 
			
		||||
        children: [],
 | 
			
		||||
        component: AddressComponent,
 | 
			
		||||
        data: {
 | 
			
		||||
          ogImage: true,
 | 
			
		||||
          networkSpecific: true,
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx',
 | 
			
		||||
        component: StartComponent,
 | 
			
		||||
        data: { preload: true, networkSpecific: true },
 | 
			
		||||
        loadChildren: () => import('../components/transaction/transaction.module').then(m => m.TransactionModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'block',
 | 
			
		||||
        component: StartComponent,
 | 
			
		||||
        data: { preload: true, networkSpecific: true },
 | 
			
		||||
        loadChildren: () => import('../components/block/block.module').then(m => m.BlockModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'assets',
 | 
			
		||||
        data: { networks: ['liquid'] },
 | 
			
		||||
        component: AssetsNavComponent,
 | 
			
		||||
        children: [
 | 
			
		||||
          {
 | 
			
		||||
            path: 'all',
 | 
			
		||||
            data: { networks: ['liquid'] },
 | 
			
		||||
            component: AssetsComponent,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'asset/:id',
 | 
			
		||||
            data: { networkSpecific: true },
 | 
			
		||||
            component: AssetComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: 'group/:id',
 | 
			
		||||
            data: { networkSpecific: true },
 | 
			
		||||
            component: AssetGroupComponent
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            path: '**',
 | 
			
		||||
            redirectTo: 'all'
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'docs',
 | 
			
		||||
        loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'api',
 | 
			
		||||
        loadChildren: () => import('../docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class LiquidRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    LiquidRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    LiquidMasterPageComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class LiquidMasterPageModule { }
 | 
			
		||||
							
								
								
									
										120
									
								
								frontend/src/app/master-page.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								frontend/src/app/master-page.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { Routes, RouterModule } from '@angular/router';
 | 
			
		||||
import { MasterPageComponent } from './components/master-page/master-page.component';
 | 
			
		||||
import { SharedModule } from './shared/shared.module';
 | 
			
		||||
 | 
			
		||||
import { StartComponent } from './components/start/start.component';
 | 
			
		||||
import { AddressComponent } from './components/address/address.component';
 | 
			
		||||
import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
 | 
			
		||||
import { BlocksList } from './components/blocks-list/blocks-list.component';
 | 
			
		||||
import { RbfList } from './components/rbf-list/rbf-list.component';
 | 
			
		||||
 | 
			
		||||
const browserWindow = window || {};
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
const browserWindowEnv = browserWindow.__env || {};
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
  {
 | 
			
		||||
    path: '',
 | 
			
		||||
    component: MasterPageComponent,
 | 
			
		||||
    children: [
 | 
			
		||||
      {
 | 
			
		||||
        path: 'mining/blocks',
 | 
			
		||||
        redirectTo: 'blocks',
 | 
			
		||||
        pathMatch: 'full'
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx/push',
 | 
			
		||||
        component: PushTransactionComponent,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'about',
 | 
			
		||||
        loadChildren: () => import('./components/about/about.module').then(m => m.AboutModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'blocks',
 | 
			
		||||
        component: BlocksList,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'rbf',
 | 
			
		||||
        component: RbfList,
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'terms-of-service',
 | 
			
		||||
        loadChildren: () => import('./components/terms-of-service/terms-of-service.module').then(m => m.TermsOfServiceModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'privacy-policy',
 | 
			
		||||
        loadChildren: () => import('./components/privacy-policy/privacy-policy.module').then(m => m.PrivacyPolicyModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'trademark-policy',
 | 
			
		||||
        loadChildren: () => import('./components/trademark-policy/trademark-policy.module').then(m => m.TrademarkModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'address/:id',
 | 
			
		||||
        children: [],
 | 
			
		||||
        component: AddressComponent,
 | 
			
		||||
        data: {
 | 
			
		||||
          ogImage: true,
 | 
			
		||||
          networkSpecific: true,
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'tx',
 | 
			
		||||
        component: StartComponent,
 | 
			
		||||
        data: { preload: true, networkSpecific: true },
 | 
			
		||||
        loadChildren: () => import('./components/transaction/transaction.module').then(m => m.TransactionModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'block',
 | 
			
		||||
        component: StartComponent,
 | 
			
		||||
        data: { preload: true, networkSpecific: true },
 | 
			
		||||
        loadChildren: () => import('./components/block/block.module').then(m => m.BlockModule),
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'docs',
 | 
			
		||||
        loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'api',
 | 
			
		||||
        loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule)
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'lightning',
 | 
			
		||||
        loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule),
 | 
			
		||||
        data: { preload: browserWindowEnv && browserWindowEnv.LIGHTNING === true, networks: ['bitcoin'] },
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  }
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    RouterModule.forChild(routes)
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    RouterModule
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class MasterPageRoutingModule { }
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  imports: [
 | 
			
		||||
    CommonModule,
 | 
			
		||||
    MasterPageRoutingModule,
 | 
			
		||||
    SharedModule,
 | 
			
		||||
  ],
 | 
			
		||||
  declarations: [
 | 
			
		||||
    MasterPageComponent,
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export class MasterPageModule { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ import { BlockPreviewComponent } from './components/block/block-preview.componen
 | 
			
		||||
import { AddressPreviewComponent } from './components/address/address-preview.component';
 | 
			
		||||
import { PoolPreviewComponent } from './components/pool/pool-preview.component';
 | 
			
		||||
import { MasterPagePreviewComponent } from './components/master-page-preview/master-page-preview.component';
 | 
			
		||||
import { TxBowtieModule } from './components/tx-bowtie-graph/tx-bowtie.module';
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
    TransactionPreviewComponent,
 | 
			
		||||
@ -23,6 +24,7 @@ import { MasterPagePreviewComponent } from './components/master-page-preview/mas
 | 
			
		||||
    RouterModule,
 | 
			
		||||
    PreviewsRoutingModule,
 | 
			
		||||
    GraphsModule,
 | 
			
		||||
    TxBowtieModule,
 | 
			
		||||
  ],
 | 
			
		||||
})
 | 
			
		||||
export class PreviewsModule { }
 | 
			
		||||
 | 
			
		||||
@ -31,7 +31,8 @@ const routes: Routes = [
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        path: 'lightning',
 | 
			
		||||
        loadChildren: () => import('./lightning/lightning-previews.module').then(m => m.LightningPreviewsModule)
 | 
			
		||||
        loadChildren: () => import('./lightning/lightning-previews.module').then(m => m.LightningPreviewsModule),
 | 
			
		||||
        data: { preload: true },
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
 | 
			
		||||
import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
 | 
			
		||||
import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITranslators,
 | 
			
		||||
  PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit } from '../interfaces/node-api.interface';
 | 
			
		||||
import { Observable, of } from 'rxjs';
 | 
			
		||||
import { BehaviorSubject, Observable, catchError, filter, of, shareReplay, take, tap } from 'rxjs';
 | 
			
		||||
import { StateService } from './state.service';
 | 
			
		||||
import { IBackendInfo, WebsocketResponse } from '../interfaces/websocket.interface';
 | 
			
		||||
import { Outspend, Transaction } from '../interfaces/electrs.interface';
 | 
			
		||||
@ -20,6 +20,8 @@ export class ApiService {
 | 
			
		||||
  private apiBaseUrl: string; // base URL is protocol, hostname, and port
 | 
			
		||||
  private apiBasePath: string; // network path is /testnet, etc. or '' for mainnet
 | 
			
		||||
 | 
			
		||||
  private requestCache = new Map<string, { subject: BehaviorSubject<any>, expiry: number }>;
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private httpClient: HttpClient,
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
@ -44,6 +46,46 @@ export class ApiService {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private generateCacheKey(functionName: string, params: any[]): string {
 | 
			
		||||
    return functionName + JSON.stringify(params);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // delete expired cache entries
 | 
			
		||||
  private cleanExpiredCache(): void {
 | 
			
		||||
    this.requestCache.forEach((value, key) => {
 | 
			
		||||
      if (value.expiry < Date.now()) {
 | 
			
		||||
        this.requestCache.delete(key);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cachedRequest<T, F extends (...args: any[]) => Observable<T>>(
 | 
			
		||||
    apiFunction: F,
 | 
			
		||||
    expireAfter: number, // in ms
 | 
			
		||||
    ...params: Parameters<F>
 | 
			
		||||
  ): Observable<T> {
 | 
			
		||||
    this.cleanExpiredCache();
 | 
			
		||||
 | 
			
		||||
    const cacheKey = this.generateCacheKey(apiFunction.name, params);
 | 
			
		||||
    if (!this.requestCache.has(cacheKey)) {
 | 
			
		||||
      const subject = new BehaviorSubject<T | null>(null);
 | 
			
		||||
      this.requestCache.set(cacheKey, { subject, expiry: Date.now() + expireAfter });
 | 
			
		||||
 | 
			
		||||
      apiFunction.bind(this)(...params).pipe(
 | 
			
		||||
        tap(data => {
 | 
			
		||||
          subject.next(data as T);
 | 
			
		||||
        }),
 | 
			
		||||
        catchError((error) => {
 | 
			
		||||
          subject.error(error);
 | 
			
		||||
          return of(null);
 | 
			
		||||
        }),
 | 
			
		||||
        shareReplay(1),
 | 
			
		||||
      ).subscribe();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this.requestCache.get(cacheKey).subject.asObservable().pipe(filter(val => val !== null), take(1));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  list2HStatistics$(): Observable<OptimizedMempoolStats[]> {
 | 
			
		||||
    return this.httpClient.get<OptimizedMempoolStats[]>(this.apiBaseUrl + this.apiBasePath + '/api/v1/statistics/2h');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -6,12 +6,8 @@ import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, fa
 | 
			
		||||
  faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faClock, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown,
 | 
			
		||||
  faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck, faCircleCheck, faUserCircle } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
 | 
			
		||||
import { MasterPageComponent } from '../components/master-page/master-page.component';
 | 
			
		||||
import { MenuComponent } from '../components/menu/menu.component';
 | 
			
		||||
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
 | 
			
		||||
import { BisqMasterPageComponent } from '../components/bisq-master-page/bisq-master-page.component';
 | 
			
		||||
import { LiquidMasterPageComponent } from '../components/liquid-master-page/liquid-master-page.component';
 | 
			
		||||
import { AboutComponent } from '../components/about/about.component';
 | 
			
		||||
import { VbytesPipe } from './pipes/bytes-pipe/vbytes.pipe';
 | 
			
		||||
import { ShortenStringPipe } from './pipes/shorten-string-pipe/shorten-string.pipe';
 | 
			
		||||
import { CeilPipe } from './pipes/math-ceil/math-ceil.pipe';
 | 
			
		||||
@ -45,9 +41,7 @@ import { AmountComponent } from '../components/amount/amount.component';
 | 
			
		||||
import { RouterModule } from '@angular/router';
 | 
			
		||||
import { CapAddressPipe } from './pipes/cap-address-pipe/cap-address-pipe';
 | 
			
		||||
import { StartComponent } from '../components/start/start.component';
 | 
			
		||||
import { TransactionComponent } from '../components/transaction/transaction.component';
 | 
			
		||||
import { TransactionsListComponent } from '../components/transactions-list/transactions-list.component';
 | 
			
		||||
import { BlockComponent } from '../components/block/block.component';
 | 
			
		||||
import { BlockOverviewGraphComponent } from '../components/block-overview-graph/block-overview-graph.component';
 | 
			
		||||
import { BlockOverviewTooltipComponent } from '../components/block-overview-tooltip/block-overview-tooltip.component';
 | 
			
		||||
import { AddressComponent } from '../components/address/address.component';
 | 
			
		||||
@ -62,13 +56,8 @@ import { FeesBoxComponent } from '../components/fees-box/fees-box.component';
 | 
			
		||||
import { DifficultyComponent } from '../components/difficulty/difficulty.component';
 | 
			
		||||
import { DifficultyTooltipComponent } from '../components/difficulty/difficulty-tooltip.component';
 | 
			
		||||
import { DifficultyMiningComponent } from '../components/difficulty-mining/difficulty-mining.component';
 | 
			
		||||
import { TermsOfServiceComponent } from '../components/terms-of-service/terms-of-service.component';
 | 
			
		||||
import { RbfTimelineComponent } from '../components/rbf-timeline/rbf-timeline.component';
 | 
			
		||||
import { RbfTimelineTooltipComponent } from '../components/rbf-timeline/rbf-timeline-tooltip.component';
 | 
			
		||||
import { TxBowtieGraphComponent } from '../components/tx-bowtie-graph/tx-bowtie-graph.component';
 | 
			
		||||
import { TxBowtieGraphTooltipComponent } from '../components/tx-bowtie-graph-tooltip/tx-bowtie-graph-tooltip.component';
 | 
			
		||||
import { PrivacyPolicyComponent } from '../components/privacy-policy/privacy-policy.component';
 | 
			
		||||
import { TrademarkPolicyComponent } from '../components/trademark-policy/trademark-policy.component';
 | 
			
		||||
import { PushTransactionComponent } from '../components/push-transaction/push-transaction.component';
 | 
			
		||||
import { AssetsFeaturedComponent } from '../components/assets/assets-featured/assets-featured.component';
 | 
			
		||||
import { AssetGroupComponent } from '../components/assets/asset-group/asset-group.component';
 | 
			
		||||
@ -141,15 +130,9 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    MempoolBlocksComponent,
 | 
			
		||||
    BlockchainBlocksComponent,
 | 
			
		||||
    AmountComponent,
 | 
			
		||||
    AboutComponent,
 | 
			
		||||
    MasterPageComponent,
 | 
			
		||||
    MenuComponent,
 | 
			
		||||
    PreviewTitleComponent,
 | 
			
		||||
    BisqMasterPageComponent,
 | 
			
		||||
    LiquidMasterPageComponent,
 | 
			
		||||
    StartComponent,
 | 
			
		||||
    TransactionComponent,
 | 
			
		||||
    BlockComponent,
 | 
			
		||||
    BlockOverviewGraphComponent,
 | 
			
		||||
    BlockOverviewTooltipComponent,
 | 
			
		||||
    TransactionsListComponent,
 | 
			
		||||
@ -166,11 +149,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    DifficultyTooltipComponent,
 | 
			
		||||
    RbfTimelineComponent,
 | 
			
		||||
    RbfTimelineTooltipComponent,
 | 
			
		||||
    TxBowtieGraphComponent,
 | 
			
		||||
    TxBowtieGraphTooltipComponent,
 | 
			
		||||
    TermsOfServiceComponent,
 | 
			
		||||
    PrivacyPolicyComponent,
 | 
			
		||||
    TrademarkPolicyComponent,
 | 
			
		||||
    PushTransactionComponent,
 | 
			
		||||
    AssetsNavComponent,
 | 
			
		||||
    AssetsFeaturedComponent,
 | 
			
		||||
@ -233,7 +211,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    AmountShortenerPipe,
 | 
			
		||||
  ],
 | 
			
		||||
  exports: [
 | 
			
		||||
    MasterPageComponent,
 | 
			
		||||
    MenuComponent,
 | 
			
		||||
    RouterModule,
 | 
			
		||||
    ReactiveFormsModule,
 | 
			
		||||
@ -275,8 +252,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    BlockchainBlocksComponent,
 | 
			
		||||
    AmountComponent,
 | 
			
		||||
    StartComponent,
 | 
			
		||||
    TransactionComponent,
 | 
			
		||||
    BlockComponent,
 | 
			
		||||
    BlockOverviewGraphComponent,
 | 
			
		||||
    BlockOverviewTooltipComponent,
 | 
			
		||||
    TransactionsListComponent,
 | 
			
		||||
@ -293,11 +268,6 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    DifficultyTooltipComponent,
 | 
			
		||||
    RbfTimelineComponent,
 | 
			
		||||
    RbfTimelineTooltipComponent,
 | 
			
		||||
    TxBowtieGraphComponent,
 | 
			
		||||
    TxBowtieGraphTooltipComponent,
 | 
			
		||||
    TermsOfServiceComponent,
 | 
			
		||||
    PrivacyPolicyComponent,
 | 
			
		||||
    TrademarkPolicyComponent,
 | 
			
		||||
    PushTransactionComponent,
 | 
			
		||||
    AssetsNavComponent,
 | 
			
		||||
    AssetsFeaturedComponent,
 | 
			
		||||
@ -320,6 +290,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
 | 
			
		||||
    ConfirmationsComponent,
 | 
			
		||||
    ToggleComponent,
 | 
			
		||||
    GeolocationComponent,
 | 
			
		||||
    TestnetAlertComponent,
 | 
			
		||||
    PreviewTitleComponent,
 | 
			
		||||
    GlobalFooterComponent,
 | 
			
		||||
    AcceleratePreviewComponent,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user