Merge branch 'master' into simon/angular-universal
* master: Update list of supported locales Add one more fix to nginx.conf for i18n Remove unused i18n tags in frontend/src/index.html Update translations from Transifex Enable 'fr' locale for French Corrected some missing spaces on transactions page and a blank render bug when confirmation time is below 1 minute. Implement i18n support in frontend using Angular + Transifex + NGINX # Conflicts: # frontend/src/app/app.constants.ts # frontend/sync-assets.js
This commit is contained in:
		
						commit
						2bba51e6c1
					
				
							
								
								
									
										7
									
								
								frontend/.tx/config
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								frontend/.tx/config
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
[main]
 | 
			
		||||
host = https://www.transifex.com
 | 
			
		||||
 | 
			
		||||
[mempool.frontend-src-locale-messages-xlf--wiz-i18n]
 | 
			
		||||
file_filter = frontend/src/locale/messages.<lang>.xlf
 | 
			
		||||
source_lang = en-US
 | 
			
		||||
type = XLIFF
 | 
			
		||||
@ -13,6 +13,70 @@
 | 
			
		||||
      "root": "",
 | 
			
		||||
      "sourceRoot": "src",
 | 
			
		||||
      "prefix": "app",
 | 
			
		||||
      "i18n": {
 | 
			
		||||
        "sourceLocale": {
 | 
			
		||||
          "code":"en-US",
 | 
			
		||||
          "baseHref":"/"
 | 
			
		||||
        },
 | 
			
		||||
        "locales": {
 | 
			
		||||
          "cs": {
 | 
			
		||||
            "translation": "src/locale/messages.cs.xlf",
 | 
			
		||||
            "baseHref": "/cs/"
 | 
			
		||||
          },
 | 
			
		||||
          "de": {
 | 
			
		||||
            "translation": "src/locale/messages.de.xlf",
 | 
			
		||||
            "baseHref": "/de/"
 | 
			
		||||
          },
 | 
			
		||||
          "es": {
 | 
			
		||||
            "translation": "src/locale/messages.es.xlf",
 | 
			
		||||
            "baseHref": "/es/"
 | 
			
		||||
          },
 | 
			
		||||
          "fa": {
 | 
			
		||||
            "translation": "src/locale/messages.fa.xlf",
 | 
			
		||||
            "baseHref": "/fa/"
 | 
			
		||||
          },
 | 
			
		||||
          "fr": {
 | 
			
		||||
            "translation": "src/locale/messages.fr.xlf",
 | 
			
		||||
            "baseHref": "/fr/"
 | 
			
		||||
          },
 | 
			
		||||
          "ja": {
 | 
			
		||||
            "translation": "src/locale/messages.ja.xlf",
 | 
			
		||||
            "baseHref": "/ja/"
 | 
			
		||||
          },
 | 
			
		||||
          "nl": {
 | 
			
		||||
            "translation": "src/locale/messages.nl.xlf",
 | 
			
		||||
            "baseHref": "/nl/"
 | 
			
		||||
          },
 | 
			
		||||
          "nn": {
 | 
			
		||||
            "translation": "src/locale/messages.nn.xlf",
 | 
			
		||||
            "baseHref": "/nn/"
 | 
			
		||||
          },
 | 
			
		||||
          "pt": {
 | 
			
		||||
            "translation": "src/locale/messages.pt.xlf",
 | 
			
		||||
            "baseHref": "/pt/"
 | 
			
		||||
          },
 | 
			
		||||
          "sl": {
 | 
			
		||||
            "translation": "src/locale/messages.sl.xlf",
 | 
			
		||||
            "baseHref": "/sl/"
 | 
			
		||||
          },
 | 
			
		||||
          "sv": {
 | 
			
		||||
            "translation": "src/locale/messages.sv.xlf",
 | 
			
		||||
            "baseHref": "/sv/"
 | 
			
		||||
          },
 | 
			
		||||
          "tr": {
 | 
			
		||||
            "translation": "src/locale/messages.tr.xlf",
 | 
			
		||||
            "baseHref": "/tr/"
 | 
			
		||||
          },
 | 
			
		||||
          "uk": {
 | 
			
		||||
            "translation": "src/locale/messages.uk.xlf",
 | 
			
		||||
            "baseHref": "/uk/"
 | 
			
		||||
          },
 | 
			
		||||
          "zh": {
 | 
			
		||||
            "translation": "src/locale/messages.zh.xlf",
 | 
			
		||||
            "baseHref": "/zh/"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "architect": {
 | 
			
		||||
        "build": {
 | 
			
		||||
          "builder": "@angular-devkit/build-angular:browser",
 | 
			
		||||
@ -176,4 +240,4 @@
 | 
			
		||||
      }
 | 
			
		||||
    }},
 | 
			
		||||
  "defaultProject": "mempool"
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								frontend/frontend
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								frontend/frontend
									
									
									
									
									
										Symbolic link
									
								
							@ -0,0 +1 @@
 | 
			
		||||
.
 | 
			
		||||
@ -22,9 +22,11 @@
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "ng": "./node_modules/@angular/cli/bin/ng",
 | 
			
		||||
    "tsc": "./node_modules/typescript/bin/tsc",
 | 
			
		||||
    "i18n-extract-from-source": "./node_modules/@angular/cli/bin/ng xi18n --ivy --out-file ./src/locale/messages.xlf",
 | 
			
		||||
    "i18n-pull-from-transifex": "tx pull -a --parallel --minimum-perc 1",
 | 
			
		||||
    "serve": "ng serve --proxy-config proxy.conf.json",
 | 
			
		||||
    "start": "npm run generate-config && npm run sync-assets-dev && ng serve --proxy-config proxy.conf.json",
 | 
			
		||||
    "build": "npm run generate-config && ng build --prod && npm run sync-assets",
 | 
			
		||||
    "build": "npm run generate-config && ng build --prod --localize && npm run sync-assets",
 | 
			
		||||
    "sync-assets": "node sync-assets.js",
 | 
			
		||||
    "sync-assets-dev": "node sync-assets.js dev",
 | 
			
		||||
    "generate-config": "node generate-config.js",
 | 
			
		||||
 | 
			
		||||
@ -33,3 +33,83 @@ export const mempoolFeeColors = [
 | 
			
		||||
 | 
			
		||||
export const feeLevels = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200,
 | 
			
		||||
  250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000];
 | 
			
		||||
 | 
			
		||||
interface Env {
 | 
			
		||||
  TESTNET_ENABLED: boolean;
 | 
			
		||||
  LIQUID_ENABLED: boolean;
 | 
			
		||||
  BISQ_ENABLED: boolean;
 | 
			
		||||
  BISQ_SEPARATE_BACKEND: boolean;
 | 
			
		||||
  SPONSORS_ENABLED: boolean;
 | 
			
		||||
  ELCTRS_ITEMS_PER_PAGE: number;
 | 
			
		||||
  KEEP_BLOCKS_AMOUNT: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultEnv: Env = {
 | 
			
		||||
  'TESTNET_ENABLED': false,
 | 
			
		||||
  'LIQUID_ENABLED': false,
 | 
			
		||||
  'BISQ_ENABLED': false,
 | 
			
		||||
  'BISQ_SEPARATE_BACKEND': false,
 | 
			
		||||
  'SPONSORS_ENABLED': false,
 | 
			
		||||
  'ELCTRS_ITEMS_PER_PAGE': 25,
 | 
			
		||||
  'KEEP_BLOCKS_AMOUNT': 8
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const browserWindow = window || {};
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
const browserWindowEnv = browserWindow.__env || {};
 | 
			
		||||
export const env: Env = Object.assign(defaultEnv, browserWindowEnv);
 | 
			
		||||
 | 
			
		||||
export interface Language {
 | 
			
		||||
  code: string;
 | 
			
		||||
  name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const languages: Language[] = [
 | 
			
		||||
// { code: 'ar', name: 'العربية' },         // Arabic
 | 
			
		||||
// { code: 'bg', name: 'Български' },       // Bulgarian
 | 
			
		||||
// { code: 'bs', name: 'Bosanski' },        // Bosnian
 | 
			
		||||
// { code: 'ca', name: 'Català' },          // Catalan
 | 
			
		||||
   { code: 'cs', name: 'Čeština' },         // Czech
 | 
			
		||||
// { code: 'da', name: 'Dansk' },           // Danish
 | 
			
		||||
   { code: 'de', name: 'Deutsch' },         // German
 | 
			
		||||
// { code: 'et', name: 'Eesti' },           // Estonian
 | 
			
		||||
// { code: 'el', name: 'Ελληνικά' },        // Greek
 | 
			
		||||
   { code: 'en', name: 'English' },         // English
 | 
			
		||||
   { code: 'es', name: 'Español' },         // Spanish
 | 
			
		||||
// { code: 'eo', name: 'Esperanto' },       // Esperanto
 | 
			
		||||
// { code: 'eu', name: 'Euskara' },         // Basque
 | 
			
		||||
   { code: 'fa', name: 'فارسی' },           // Persian
 | 
			
		||||
   { code: 'fr', name: 'Français' },        // French
 | 
			
		||||
// { code: 'gl', name: 'Galego' },          // Galician
 | 
			
		||||
// { code: 'ko', name: '한국어' },          // Korean
 | 
			
		||||
// { code: 'hr', name: 'Hrvatski' },        // Croatian
 | 
			
		||||
// { code: 'id', name: 'Bahasa Indonesia' },// Indonesian
 | 
			
		||||
// { code: 'it', name: 'Italiano' },        // Italian
 | 
			
		||||
// { code: 'he', name: 'עברית' },           // Hebrew
 | 
			
		||||
// { code: 'ka', name: 'ქართული' },         // Georgian
 | 
			
		||||
// { code: 'lv', name: 'Latviešu' },        // Latvian
 | 
			
		||||
// { code: 'lt', name: 'Lietuvių' },        // Lithuanian
 | 
			
		||||
// { code: 'hu', name: 'Magyar' },          // Hungarian
 | 
			
		||||
// { code: 'mk', name: 'Македонски' },      // Macedonian
 | 
			
		||||
// { code: 'ms', name: 'Bahasa Melayu' },   // Malay
 | 
			
		||||
   { code: 'nl', name: 'Nederlands' },      // Dutch
 | 
			
		||||
   { code: 'ja', name: '日本語' },          // Japanese
 | 
			
		||||
// { code: 'nb', name: 'Norsk bokmål' },    // Norwegian Bokmål
 | 
			
		||||
   { code: 'nn', name: 'Norsk' },           // Norwegian Nynorsk
 | 
			
		||||
// { code: 'pl', name: 'Polski' },          // Polish
 | 
			
		||||
   { code: 'pt', name: 'Português' },       // Portuguese
 | 
			
		||||
// { code: 'pt-BR', name: 'Português (Brazil)' }, // Portuguese (Brazil)
 | 
			
		||||
// { code: 'ro', name: 'Română' },          // Romanian
 | 
			
		||||
// { code: 'ru', name: 'Русский' },         // Russian
 | 
			
		||||
// { code: 'sk', name: 'Slovenčina' },      // Slovak
 | 
			
		||||
   { code: 'sl', name: 'Slovenščina' },     // Slovenian
 | 
			
		||||
// { code: 'sr', name: 'Српски / srpski' }, // Serbian
 | 
			
		||||
// { code: 'sh', name: 'Srpskohrvatski / српскохрватски' },// Serbo-Croatian
 | 
			
		||||
// { code: 'fi', name: 'Suomi' },           // Finnish
 | 
			
		||||
   { code: 'sv', name: 'Svenska' },         // Swedish
 | 
			
		||||
// { code: 'th', name: 'ไทย' },             // Thai
 | 
			
		||||
   { code: 'tr', name: 'Türkçe' },          // Turkish
 | 
			
		||||
   { code: 'uk', name: 'Українська' },      // Ukrainian
 | 
			
		||||
// { code: 'vi', name: 'Tiếng Việt' },      // Vietnamese
 | 
			
		||||
   { code: 'zh', name: '中文' },            // Chinese
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,7 @@ import { faAngleDoubleDown, faAngleDoubleUp, faAngleDown, faAngleUp, faBolt, faC
 | 
			
		||||
  faLink, faList, faSearch, faTachometerAlt, faThList, faTint, faTv } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { ApiDocsComponent } from './components/api-docs/api-docs.component';
 | 
			
		||||
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
 | 
			
		||||
import { TranslationStringsComponent } from './components/translation-strings/translation-strings.component';
 | 
			
		||||
import { StorageService } from './services/storage.service';
 | 
			
		||||
import { HttpCacheInterceptor } from './services/http-cache.interceptor';
 | 
			
		||||
 | 
			
		||||
@ -83,6 +84,7 @@ import { HttpCacheInterceptor } from './services/http-cache.interceptor';
 | 
			
		||||
    DashboardComponent,
 | 
			
		||||
    ApiDocsComponent,
 | 
			
		||||
    TermsOfServiceComponent,
 | 
			
		||||
    TranslationStringsComponent,
 | 
			
		||||
  ],
 | 
			
		||||
  imports: [
 | 
			
		||||
    BrowserModule.withServerTransition({ appId: 'serverApp' }),
 | 
			
		||||
 | 
			
		||||
@ -10,16 +10,16 @@
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>About the project</h2>
 | 
			
		||||
    <h2 i18n="about.about-the-project">About the project</h2>
 | 
			
		||||
    <div class="row row-cols-1">
 | 
			
		||||
      <div class="col col-md-6 offset-md-3">
 | 
			
		||||
        <p>The mempool open-source project aims to implement a high quality explorer and visualization website for the entire Bitcoin ecosystem, without distractions like altcoins, advertising, or third-party trackers.</p>
 | 
			
		||||
        <p i18n>The mempool open-source project aims to implement a high quality explorer and visualization website for the entire Bitcoin ecosystem, without distractions like altcoins, advertising, or third-party trackers.</p>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2>Maintainers</h2>
 | 
			
		||||
    <h2 i18n="about.maintainers">Maintainers</h2>
 | 
			
		||||
 | 
			
		||||
    <div class="container text-center">
 | 
			
		||||
      <div class="row row-cols-2">
 | 
			
		||||
@ -29,7 +29,7 @@
 | 
			
		||||
            @softsimon_
 | 
			
		||||
          </a>
 | 
			
		||||
          <br>
 | 
			
		||||
          Development
 | 
			
		||||
          <span i18n="about.development">Development</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col col-md-2">
 | 
			
		||||
          <a href="https://twitter.com/wiz">
 | 
			
		||||
@ -37,14 +37,14 @@
 | 
			
		||||
            @wiz
 | 
			
		||||
          </a>
 | 
			
		||||
          <br>
 | 
			
		||||
          Operations
 | 
			
		||||
          <span i18n="about.operations">Operations</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br><br>
 | 
			
		||||
 | 
			
		||||
    <h2>Sponsors ❤️</h2>
 | 
			
		||||
    <h2 i18n="about.sponsors.withHeart">Sponsors ❤️</h2>
 | 
			
		||||
 | 
			
		||||
    <div *ngIf="sponsors === null">
 | 
			
		||||
      <br>
 | 
			
		||||
@ -60,9 +60,9 @@
 | 
			
		||||
    </ng-template>
 | 
			
		||||
    <br><br>
 | 
			
		||||
    
 | 
			
		||||
    <button type="button" class="btn btn-primary" (click)="donationStatus = 2" [hidden]="donationStatus !== 1">Become a sponsor ❤️</button>
 | 
			
		||||
    <button type="button" class="btn btn-primary" (click)="donationStatus = 2" [hidden]="donationStatus !== 1" i18n="about.become-a-sponsor">Become a sponsor ❤️</button>
 | 
			
		||||
    <p *ngIf="donationStatus === 2 && !sponsorsEnabled">
 | 
			
		||||
      Navigate to <a href="https://mempool.space/about" target="_blank">https://mempool.space/about</a> to sponsor
 | 
			
		||||
      <span i18n="about.navigate-to">Navigate to</span> <a href="https://mempool.space/about" target="_blank">https://mempool.space/about</a> <span i18n="about.to-sponsor">to sponsor</span>
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <div style="max-width: 300px;" class="mx-auto" [hidden]="donationStatus !== 2 || !sponsorsEnabled">
 | 
			
		||||
@ -79,17 +79,17 @@
 | 
			
		||||
          </div>
 | 
			
		||||
          <input formControlName="handle" class="form-control" type="text" placeholder="Twitter handle (Optional)">
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="required" *ngIf="donationForm.get('amount').hasError('required')">Amount required</div>
 | 
			
		||||
        <div class="required" *ngIf="donationForm.get('amount').hasError('min')">Minimum amount is 0.001 BTC</div>
 | 
			
		||||
        <div class="required" *ngIf="donationForm.get('amount').hasError('required')" i18n="about.sponsor.amount-required">Amount required</div>
 | 
			
		||||
        <div class="required" *ngIf="donationForm.get('amount').hasError('min')" i18n="about.sponsor.minimum-amount">Minimum amount is 0.001 BTC</div>
 | 
			
		||||
        <div class="input-group mt-4">
 | 
			
		||||
          <button class="btn btn-primary mx-auto" type="submit" [disabled]="donationForm.invalid">Request invoice</button>
 | 
			
		||||
          <button class="btn btn-primary mx-auto" type="submit" [disabled]="donationForm.invalid" i18n="about.sponsor.request-invoice">Request invoice</button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </form>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <ng-template #lowAmount>
 | 
			
		||||
      <div class="input-group mb-4 text-small">
 | 
			
		||||
        If you donate 0.01 BTC or more, your profile photo will be added to the list of sponsors above :)
 | 
			
		||||
        <span i18n="about.sponsor.description">If you donate 0.01 BTC or more, your profile photo will be added to the list of sponsors above :)</span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
@ -167,13 +167,13 @@
 | 
			
		||||
        <p style="font-size: 12px;">{{ donationObj.amount }} BTC</p>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
 | 
			
		||||
      <p>Waiting for transaction... </p>
 | 
			
		||||
      <p i18n="about.sponsor.waiting-for-transaction">Waiting for transaction... </p>
 | 
			
		||||
      <div class="spinner-border text-light"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div *ngIf="donationStatus === 4" class="text-center">
 | 
			
		||||
      <h2>Donation confirmed!<br>Thank you!</h2>
 | 
			
		||||
      <p>If you specified a Twitter handle, the profile photo should now be visible on this page when you reload.</p>
 | 
			
		||||
      <h2><span i18n="about.sponsor.donation-confirmed">Donation confirmed!</span><br><span i18n="about.sponsor.thank-you">Thank you!</span></h2>
 | 
			
		||||
      <p i18n="about.sponsor.sponsor-completed">If you specified a Twitter handle, the profile photo should now be visible on this page when you reload.</p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <br><br><br><br>
 | 
			
		||||
@ -203,7 +203,7 @@
 | 
			
		||||
  <br><br>
 | 
			
		||||
 | 
			
		||||
  <div class="text-center">
 | 
			
		||||
    <a [routerLink]="['/terms-of-service']">Terms of Service</a>
 | 
			
		||||
    <a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -1,2 +1,2 @@
 | 
			
		||||
<span *ngIf="multisig" class="badge badge-pill badge-warning">multisig {{ multisigM }} of {{ multisigN }}</span>
 | 
			
		||||
<span *ngIf="secondLayerClose" class="badge badge-pill badge-warning">Layer{{ network === 'liquid' ? '3' : '2' }} Peg-out</span>
 | 
			
		||||
<span *ngIf="multisig" class="badge badge-pill badge-warning" i18n="address-labels.multisig">multisig {{ multisigM }} of {{ multisigN }}</span>
 | 
			
		||||
<span *ngIf="secondLayerClose" class="badge badge-pill badge-warning" i18n="address-labels.upper-layer-peg-out">Layer{{ network === 'liquid' ? '3' : '2' }} Peg-out</span>
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
  <h1 style="float: left;">Address</h1>
 | 
			
		||||
  <h1 style="float: left;" i18n="shared.address">Address</h1>
 | 
			
		||||
  <a [routerLink]="['/address/' | relativeUrl, addressString]" style="line-height: 56px; margin-left: 10px;">
 | 
			
		||||
    <span class="d-inline d-lg-none">{{ addressString | shortenString : 24 }}</span>
 | 
			
		||||
    <span class="d-none d-lg-inline">{{ addressString }}</span>
 | 
			
		||||
@ -17,15 +17,15 @@
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Total received</td>
 | 
			
		||||
                <td i18n="address.total-received">Total received</td>
 | 
			
		||||
                <td *ngIf="address.chain_stats.funded_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="receieved" [noFiat]="true"></app-amount></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Total sent</td>
 | 
			
		||||
                <td i18n="address.total-sent">Total sent</td>
 | 
			
		||||
                <td *ngIf="address.chain_stats.spent_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="sent" [noFiat]="true"></app-amount></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Balance</td>
 | 
			
		||||
                <td i18n="address.balance">Balance</td>
 | 
			
		||||
                <td *ngIf="address.chain_stats.funded_txo_sum !== undefined; else confidentialTd"><app-amount [satoshis]="receieved - sent" [noFiat]="true"></app-amount> (<app-fiat [value]="receieved - sent"></app-fiat>)</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
@ -43,7 +43,7 @@
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2><ng-template [ngIf]="transactions?.length">{{ (transactions?.length | number) || '?' }} of </ng-template>{{ txCount | number }} transactions</h2>
 | 
			
		||||
    <h2><ng-template [ngIf]="transactions?.length">{{ (transactions?.length | number) || '?' }} <span i18n="shared.of">of</span> </ng-template>{{ txCount | number }} <span i18n="shared.transactions">transactions</span></h2>
 | 
			
		||||
 | 
			
		||||
    <app-transactions-list [transactions]="transactions" [showConfirmations]="true" (loadMore)="loadMore()"></app-transactions-list>
 | 
			
		||||
 | 
			
		||||
@ -98,7 +98,7 @@
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="error">
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      Error loading address data.
 | 
			
		||||
      <span i18n="address.error.loading-address-data">Error loading address data.</span>
 | 
			
		||||
      <br>
 | 
			
		||||
      <i>{{ error.error }}</i>
 | 
			
		||||
    </div>
 | 
			
		||||
@ -109,5 +109,5 @@
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
<ng-template #confidentialTd>
 | 
			
		||||
  <td>Confidential</td>
 | 
			
		||||
  <td i18n="shared.confidential">Confidential</td>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
</ng-container>
 | 
			
		||||
<ng-template #viewFiatVin>
 | 
			
		||||
  <ng-template [ngIf]="network === 'liquid' && (satoshis === undefined || satoshis === null)" [ngIfElse]="default">
 | 
			
		||||
    Confidential
 | 
			
		||||
    <span i18n="shared.confidential">Confidential</span>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
  <ng-template #default>
 | 
			
		||||
    {{ satoshis / 100000000 | number : digitsInfo }}
 | 
			
		||||
 | 
			
		||||
@ -6,17 +6,17 @@
 | 
			
		||||
 | 
			
		||||
  <ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs">
 | 
			
		||||
    <li *ngIf="network.val !== 'bisq'" [ngbNavItem]="0">
 | 
			
		||||
      <a ngbNavLink>Websocket</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.websocket|API Docs tab for Websocket">Websocket</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap">wss://{{ hostname }}{{ network.val === '' ? '' : '/' + network.val }}/api/v1/ws</td>
 | 
			
		||||
            <td>Default push: <code>{{ '{' }} action: 'want', data: ['blocks', ...] {{ '}' }}</code> to express what you want pushed. Available: <code>blocks</code>, <code>mempool-block</code>, <code>live-2h-chart</code>, and <code>stats</code>.<br><br>Push transactions related to address: <code>{{ '{' }} 'track-address': '3PbJ...bF9B' {{ '}' }}</code> to receive all new transactions containing that address as input or output. Returns an array of transactions. <code>address-transactions</code> for new mempool transactions, and <code>block-transactions</code> for new block confirmed transactions.</td>
 | 
			
		||||
            <td i18n="api-docs.websocket.websocket">Default push: <code>{{ '{' }} action: 'want', data: ['blocks', ...] {{ '}' }}</code> to express what you want pushed. Available: <code>blocks</code>, <code>mempool-block</code>, <code>live-2h-chart</code>, and <code>stats</code>.<br><br>Push transactions related to address: <code>{{ '{' }} 'track-address': '3PbJ...bF9B' {{ '}' }}</code> to receive all new transactions containing that address as input or output. Returns an array of transactions. <code>address-transactions</code> for new mempool transactions, and <code>block-transactions</code> for new block confirmed transactions.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -24,21 +24,21 @@
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val !== 'bisq'" [ngbNavItem]="1">
 | 
			
		||||
      <a ngbNavLink>Fee Estimates</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.fees|API Docs tab for Fees">Fees</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/recommended" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/recommended</a></td>
 | 
			
		||||
            <td>Returns our currently suggested fees for new transactions.</td>
 | 
			
		||||
            <td i18n="api-docs.fees.recommended|API Docs for /api/v1/fees/recommended">Returns our currently suggested fees for new transactions.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/mempool-blocks" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/mempool-blocks</a></td>
 | 
			
		||||
            <td>Returns current mempool as projected blocks.</td>
 | 
			
		||||
            <td i18n="api-docs.fees.mempool-blocks|API Docs for /api/v1/fees/mempool-blocks">Returns current mempool as projected blocks.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -46,25 +46,25 @@
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val !== 'bisq'" [ngbNavItem]="2">
 | 
			
		||||
      <a ngbNavLink>Mempool</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.mempool|API Docs tab for Mempool">Mempool</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/mempool" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/mempool</a></td>
 | 
			
		||||
            <td>Returns current mempool backlog statistics.</td>
 | 
			
		||||
            <td i18n="api-docs.mempool.mempool|API Docs for /api/mempool">Returns current mempool backlog statistics.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/mempool/txids" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/mempool/txids</a></td>
 | 
			
		||||
            <td>Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.</td>
 | 
			
		||||
            <td i18n="api-docs.mempool.txids|API Docs for /api/mempool/txids">Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/mempool/recent" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/mempool/recent</a></td>
 | 
			
		||||
            <td>Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: <code>txid</code>, <code>fee</code>, <code>vsize</code>, and <code>value</code>.</td>
 | 
			
		||||
            <td i18n="api-docs.mempool.recent|API Docs for /api/mempool/recent">Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: <code>txid</code>, <code>fee</code>, <code>vsize</code>, and <code>value</code>.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -72,53 +72,53 @@
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val !== 'bisq'" [ngbNavItem]="3">
 | 
			
		||||
      <a ngbNavLink>Blocks</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.blocks|API Docs tab for Blocks">Blocks</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block/000000000000000015dc777b3ff2611091336355d3f0ee9766a2cf3be8e4b1ce" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash</a></td>
 | 
			
		||||
            <td>Returns details about a block. Available fields: <code>id</code>, <code>height</code>, <code>version</code>, <code>timestamp</code>, <code>bits</code>, <code>nonce</code>, <code>merkle_root</code>, <code>tx_count</code>, <code>size</code>, <code>weight</code>,<ng-container *ngIf="network.val === 'liquid'"> <code>proof</code>,</ng-container> and <code>previousblockhash</code>.</td>
 | 
			
		||||
            <td i18n>Returns details about a block. Available fields: <code>id</code>, <code>height</code>, <code>version</code>, <code>timestamp</code>, <code>bits</code>, <code>nonce</code>, <code>merkle_root</code>, <code>tx_count</code>, <code>size</code>, <code>weight</code>,<ng-container *ngIf="network.val === 'liquid'"> <code>proof</code>,</ng-container> and <code>previousblockhash</code>.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block/000000000000000015dc777b3ff2611091336355d3f0ee9766a2cf3be8e4b1ce/status" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/status</a></td>
 | 
			
		||||
            <td>Returns the confirmation status of a block. Available fields: <code>in_best_chain</code> (boolean, false for orphaned blocks), <code>next_best</code> (the hash of the next block, only available for blocks in the best chain).</td>
 | 
			
		||||
            <td i18n>Returns the confirmation status of a block. Available fields: <code>in_best_chain</code> (boolean, false for orphaned blocks), <code>next_best</code> (the hash of the next block, only available for blocks in the best chain).</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block/000000000000000015dc777b3ff2611091336355d3f0ee9766a2cf3be8e4b1ce/txs" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txs[/:start_index]</a></td>
 | 
			
		||||
            <td>Returns a list of transactions in the block (up to 25 transactions beginning at <code>start_index</code>). Transactions returned here do not have the <code>status</code> field, since all the transactions share the same block and confirmation status.</td>
 | 
			
		||||
            <td i18n>Returns a list of transactions in the block (up to 25 transactions beginning at <code>start_index</code>). Transactions returned here do not have the <code>status</code> field, since all the transactions share the same block and confirmation status.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block/000000000000000015dc777b3ff2611091336355d3f0ee9766a2cf3be8e4b1ce/txids" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txids</a></td>
 | 
			
		||||
            <td>Returns a list of all txids in the block.</td>
 | 
			
		||||
            <td i18n>Returns a list of all txids in the block.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block/000000000000000015dc777b3ff2611091336355d3f0ee9766a2cf3be8e4b1ce/txid/218" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txid/:index</a></td>
 | 
			
		||||
            <td>Returns the transaction at index <code>:index</code> within the specified block.</td>
 | 
			
		||||
            <td i18n>Returns the transaction at index <code>:index</code> within the specified block.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block/000000000000000015dc777b3ff2611091336355d3f0ee9766a2cf3be8e4b1ce/raw" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block/:hash/txid/raw</a></td>
 | 
			
		||||
            <td>Returns the raw block representation in binary.</td>
 | 
			
		||||
            <td i18n>Returns the raw block representation in binary.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/block-height/0" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/block-height/:height</a></td>
 | 
			
		||||
            <td>Returns the hash of the block currently at <code>:height</code>.</td>
 | 
			
		||||
            <td i18n>Returns the hash of the block currently at <code>:height</code>.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/blocks" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/blocks[/:start_height]</a></td>
 | 
			
		||||
            <td>Returns the 10 newest blocks starting at the tip or at <code>:start_height</code> if specified.</td>
 | 
			
		||||
            <td i18n>Returns the 10 newest blocks starting at the tip or at <code>:start_height</code> if specified.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/blocks/tip/height" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/blocks/tip/height</a></td>
 | 
			
		||||
            <td>Returns the height of the last block.</td>
 | 
			
		||||
            <td i18n>Returns the height of the last block.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/blocks/tip/hash" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/blocks/tip/hash</a></td>
 | 
			
		||||
            <td>Returns the hash of the last block.</td>
 | 
			
		||||
            <td i18n>Returns the hash of the last block.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -126,49 +126,49 @@
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val !== 'bisq'" [ngbNavItem]="4">
 | 
			
		||||
      <a ngbNavLink>Transactions</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.transactions|API Docs tab for Transactions">Transactions</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid</a></td>
 | 
			
		||||
            <td>Returns details about a transaction. Available fields: <code>txid</code>, <code>version</code>, <code>locktime</code>, <code>size</code>, <code>weight</code>, <code>fee</code>, <code>vin</code>, <code>vout</code>, and <code>status</code>.</td>
 | 
			
		||||
            <td i18n>Returns details about a transaction. Available fields: <code>txid</code>, <code>version</code>, <code>locktime</code>, <code>size</code>, <code>weight</code>, <code>fee</code>, <code>vin</code>, <code>vout</code>, and <code>status</code>.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/status" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/status</a></td>
 | 
			
		||||
            <td>Returns the confirmation status of a transaction. Available fields: <code>confirmed</code> (boolean), <code>block_height</code> (optional), and <code>block_hash</code> (optional).</td>
 | 
			
		||||
            <td i18n>Returns the confirmation status of a transaction. Available fields: <code>confirmed</code> (boolean), <code>block_height</code> (optional), and <code>block_hash</code> (optional).</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/hex" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/hex</a></td>
 | 
			
		||||
            <td>Returns a transaction serialized as hex.</td>
 | 
			
		||||
            <td i18n>Returns a transaction serialized as hex.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/raw" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/raw</a></td>
 | 
			
		||||
            <td>Returns a transaction as binary data.</td>
 | 
			
		||||
            <td i18n>Returns a transaction as binary data.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr *ngIf="network.val !== 'liquid'">
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/merkleblock-proof" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/merkleblock-proof</a></td>
 | 
			
		||||
            <td>Returns a merkle inclusion proof for the transaction using <a href="https://bitcoin.org/en/glossary/merkle-block">bitcoind's merkleblock</a> format.</td>
 | 
			
		||||
            <td i18n>Returns a merkle inclusion proof for the transaction using <a href="https://bitcoin.org/en/glossary/merkle-block">bitcoind's merkleblock</a> format.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/merkle-proof" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/merkle-proof</a></td>
 | 
			
		||||
            <td>Returns a merkle inclusion proof for the transaction using <a href="https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle">Electrum's blockchain.transaction.get_merkle format.</a></td>
 | 
			
		||||
            <td i18n>Returns a merkle inclusion proof for the transaction using <a href="https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle">Electrum's blockchain.transaction.get_merkle format.</a></td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/outspend/3" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/outspend/:vout</a></td>
 | 
			
		||||
            <td>Returns the spending status of a transaction output. Available fields: <code>spent</code> (boolean), <code>txid</code> (optional), <code>vin</code> (optional), and <code>status</code> (optional, the status of the spending tx).</td>
 | 
			
		||||
            <td i18n>Returns the spending status of a transaction output. Available fields: <code>spent</code> (boolean), <code>txid</code> (optional), <code>vin</code> (optional), and <code>status</code> (optional, the status of the spending tx).</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/tx/15e10745f15593a899cef391191bdd3d7c12412cc4696b7bcb669d0feadc8521/outspends" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/tx/:txid/outspends</a></td>
 | 
			
		||||
            <td>Returns the spending status of all transaction outputs.</td>
 | 
			
		||||
            <td i18n>Returns the spending status of all transaction outputs.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap">POST {{ network.val === '' ? '' : '/' + network.val }}/api/tx</td>
 | 
			
		||||
            <td>Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The <code>txid</code> will be returned on success.</td>
 | 
			
		||||
            <td i18n>Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The <code>txid</code> will be returned on success.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -176,33 +176,33 @@
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val !== 'bisq'" [ngbNavItem]="5">
 | 
			
		||||
      <a ngbNavLink>Addresses</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.addresses|API Docs tab for Addresses">Addresses</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address</a></td>
 | 
			
		||||
            <td>Returns details about an address. Available fields: <code>address</code>, <code>chain_stats</code>, and <code>mempool_stats</code>. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with <code>tx_count</code>, <code>funded_txo_count</code>, <code>funded_txo_sum</code>, <code>spent_txo_count</code>, and <code>spent_txo_sum</code>.</td>
 | 
			
		||||
            <td i18n>Returns details about an address. Available fields: <code>address</code>, <code>chain_stats</code>, and <code>mempool_stats</code>. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with <code>tx_count</code>, <code>funded_txo_count</code>, <code>funded_txo_sum</code>, <code>spent_txo_count</code>, and <code>spent_txo_sum</code>.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC/txs" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/txs</a></td>
 | 
			
		||||
            <td>Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using <code>:last_seen_txid</code> (see below).
 | 
			
		||||
            <td i18n>Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using <code>:last_seen_txid</code> (see below).
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC/txs/chain" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/txs/chain</a></td>
 | 
			
		||||
            <td>Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.</td>
 | 
			
		||||
            <td i18n>Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC/txs/mempool" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/txs/mempool</a></td>
 | 
			
		||||
            <td>Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).</td>
 | 
			
		||||
            <td i18n>Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC/utxo" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/address/:address/utxo</a></td>
 | 
			
		||||
            <td>Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: <code>txid</code>, <code>vout</code>, <code>value</code>, and <code>status</code> (with the status of the funding tx).<ng-container *ngIf="network.val === 'liquid'">There is also a <code>valuecommitment</code> field that may appear in place of <code>value</code>, plus the following additional fields: <code>asset</code>/<code>assetcommitment</code>, <code>nonce</code>/<code>noncecommitment</code>, <code>surjection_proof</code>, and <code>range_proof</code>.</ng-container></td>
 | 
			
		||||
            <td i18n>Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: <code>txid</code>, <code>vout</code>, <code>value</code>, and <code>status</code> (with the status of the funding tx).<ng-container *ngIf="network.val === 'liquid'">There is also a <code>valuecommitment</code> field that may appear in place of <code>value</code>, plus the following additional fields: <code>asset</code>/<code>assetcommitment</code>, <code>nonce</code>/<code>noncecommitment</code>, <code>surjection_proof</code>, and <code>range_proof</code>.</ng-container></td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
 | 
			
		||||
@ -210,66 +210,66 @@
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val === 'liquid'" [ngbNavItem]="6">
 | 
			
		||||
      <a ngbNavLink>Assets</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.assets|API Docs tab for Assets">Assets</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/liquid/api/asset/6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d" target="_blank">GET /liquid/api/asset/:asset_id</a></td>
 | 
			
		||||
            <td>Returns information about a Liquid asset.</td>
 | 
			
		||||
            <td i18n>Returns information about a Liquid asset.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/liquid/api/asset/4b5417ec5ab6112bedf539c3b4f5a806ed539542d8b717e1c4470aa3180edce5/txs" target="_blank">GET /liquid/api/asset/:asset_id/txs[/mempool|/chain]</a></td>
 | 
			
		||||
            <td>Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.</td>
 | 
			
		||||
            <td i18n>Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/liquid/api/asset/4b5417ec5ab6112bedf539c3b4f5a806ed539542d8b717e1c4470aa3180edce5/supply" target="_blank">GET /liquid/api/asset/:asset_id/supply[/decimal]</a></td>
 | 
			
		||||
            <td>Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.</td>
 | 
			
		||||
            <td i18n>Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
    </li>
 | 
			
		||||
 | 
			
		||||
    <li *ngIf="network.val === 'bisq'" [ngbNavItem]="1">
 | 
			
		||||
      <a ngbNavLink>BSQ</a>
 | 
			
		||||
      <a ngbNavLink i18n="api-docs.tab.bsq|API Docs tab for BSQ">BSQ</a>
 | 
			
		||||
      <ng-template ngbNavContent>
 | 
			
		||||
 | 
			
		||||
        <table class="table">
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th style="border-top: 0;">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;">Description</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.endpoint|API Docs Endpoint">Endpoint</th>
 | 
			
		||||
            <th style="border-top: 0;" i18n="api-docs.shared.description|API Docs Description">Description</th>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/stats" target="_blank">GET /bisq/api/stats</a></td>
 | 
			
		||||
            <td>Returns statistics about all Bisq transactions.</td>
 | 
			
		||||
            <td i18n>Returns statistics about all Bisq transactions.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/tx/4b5417ec5ab6112bedf539c3b4f5a806ed539542d8b717e1c4470aa3180edce5" target="_blank">GET /bisq/api/tx/:txid</a></td>
 | 
			
		||||
            <td>Returns details about a Bisq transaction.</td>
 | 
			
		||||
            <td i18n>Returns details about a Bisq transaction.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/txs/0/25" target="_blank">GET /bisq/api/txs/:index/:length</a></td>
 | 
			
		||||
            <td>Returns :length of latest Bisq transactions, starting from :index.</td>
 | 
			
		||||
            <td i18n>Returns :length of latest Bisq transactions, starting from :index.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/block/000000000000000000079aa6bfa46eb8fc20474e8673d6e8a123b211236bf82d" target="_blank">GET /bisq/api/block/:hash</a></td>
 | 
			
		||||
            <td>Returns all Bisq transactions that exist in a Bitcoin block.</td>
 | 
			
		||||
            <td i18n>Returns all Bisq transactions that exist in a Bitcoin block.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/blocks/0/25" target="_blank">GET /bisq/api/blocks/:index/:length</a></td>
 | 
			
		||||
            <td>Returns :length Bitcoin blocks that contain Bisq transactions, starting from :index.</td>
 | 
			
		||||
            <td i18n>Returns :length Bitcoin blocks that contain Bisq transactions, starting from :index.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/blocks/tip/height" target="_blank">GET /bisq/api/blocks/tip/height</a></td>
 | 
			
		||||
            <td>Returns the most recently processed Bitcoin block height processed by Bisq.</td>
 | 
			
		||||
            <td i18n>Returns the most recently processed Bitcoin block height processed by Bisq.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td class="nowrap"><a href="/bisq/api/address/B1DgwRN92rdQ9xpEVCdXRfgeqGw9X4YtrZz" target="_blank">GET /bisq/api/address/:address</a></td>
 | 
			
		||||
            <td>Returns all Bisq transactions belonging to a Bitcoin address, with 'B' prefixed in front of the address.</td>
 | 
			
		||||
            <td i18n>Returns all Bisq transactions belonging to a Bitcoin address, with 'B' prefixed in front of the address.</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </table>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
@ -281,7 +281,7 @@
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
  <div class="text-center">
 | 
			
		||||
    <a [routerLink]="['/terms-of-service']">Terms of Service</a>
 | 
			
		||||
    <a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -17,19 +17,19 @@
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Name</td>
 | 
			
		||||
                <td i18n="asset.name|Liquid Asset name">Name</td>
 | 
			
		||||
                <td>{{ assetContract[2] }} ({{ assetContract[1] }})</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Precision</td>
 | 
			
		||||
                <td i18n="asset.precision|Liquid Asset precision">Precision</td>
 | 
			
		||||
                <td>{{ assetContract[3] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr *ngIf="!isNativeAsset && assetContract[0]">
 | 
			
		||||
                <td>Issuer</td>
 | 
			
		||||
                <td i18n="asset.issuer|Liquid Asset issuer">Issuer</td>
 | 
			
		||||
                <td><a target="_blank" href="{{ 'http://' + assetContract[0] }}">{{ assetContract[0] }}</a></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr *ngIf="!isNativeAsset">
 | 
			
		||||
                <td>Issuance tx</td>
 | 
			
		||||
                <td i18n="asset.issuance-tx|Liquid Asset issuance TX">Issuance TX</td>
 | 
			
		||||
                <td><a [routerLink]="['/tx/' | relativeUrl, asset.issuance_txin.txid]">{{ asset.issuance_txin.txid | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="asset.issuance_txin.txid"></app-clipboard></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
@ -40,27 +40,27 @@
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr *ngIf="isNativeAsset">
 | 
			
		||||
                <td>Pegged in</td>
 | 
			
		||||
                <td i18n="asset.pegged-in|Liquid Asset pegged-in amount">Pegged in</td>
 | 
			
		||||
                <td>{{ formatAmount(asset.chain_stats.peg_in_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr *ngIf="isNativeAsset">
 | 
			
		||||
                <td>Pegged out</td>
 | 
			
		||||
                <td i18n="asset.pegged-out|Liquid Asset pegged-out amount">Pegged out</td>
 | 
			
		||||
                <td>{{ formatAmount(asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr *ngIf="!isNativeAsset">
 | 
			
		||||
                <td>Issued amount</td>
 | 
			
		||||
                <td i18n="asset.issued-amount|Liquid Asset issued amount">Issued amount</td>
 | 
			
		||||
                <td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.issued_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Burned amount</td>
 | 
			
		||||
                <td i18n="asset.burned-amount|Liquid Asset burned amount">Burned amount</td>
 | 
			
		||||
                <td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr *ngIf="!isNativeAsset">
 | 
			
		||||
                <td>Circulating amount</td>
 | 
			
		||||
                <td i18n="asset.circulating-amount|Liquid Asset circulating amount">Circulating amount</td>
 | 
			
		||||
                <td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.issued_amount - asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr *ngIf="isNativeAsset">
 | 
			
		||||
                <td>Circulating amount</td>
 | 
			
		||||
                <td i18n="asset.circulating-amount|Liquid Asset circulating amount">Circulating amount</td>
 | 
			
		||||
                <td>{{ formatAmount(asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
@ -129,7 +129,7 @@
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="error">
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      Error loading asset data.
 | 
			
		||||
      <span i18n="asset.error.loading-asset-data">Error loading asset data.</span>
 | 
			
		||||
      <br>
 | 
			
		||||
      <i>{{ error.error }}</i>
 | 
			
		||||
    </div>
 | 
			
		||||
@ -140,5 +140,5 @@
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
<ng-template #confidentialTd>
 | 
			
		||||
  <td>Confidential</td>
 | 
			
		||||
  <td i18n="shared.confidential">Confidential</td>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
<div class="container-xl">
 | 
			
		||||
 | 
			
		||||
  <div class="title-block">
 | 
			
		||||
    <h1 class="float-left"><ng-template [ngIf]="blockHeight === 0">Genesis </ng-template>Block <ng-template [ngIf]="blockHeight"><a [routerLink]="['/block/' | relativeUrl, blockHash]">{{ blockHeight }}</a></ng-template></h1>
 | 
			
		||||
    <h1 class="float-left"><ng-template [ngIf]="blockHeight === 0" i18n="block.genesis">Genesis </ng-template><ng-template [ngIf]="blockHeight" i18n="block.block">Block <a [routerLink]="['/block/' | relativeUrl, blockHash]">{{ blockHeight }}</a></ng-template></h1>
 | 
			
		||||
    <button [routerLink]="['/' | relativeUrl]" class="btn btn-sm float-right mr-2 mt-2">✕</button>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
@ -15,24 +15,24 @@
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td class="td-width">Hash</td>
 | 
			
		||||
                <td class="td-width" i18n="block.hash">Hash</td>
 | 
			
		||||
                <td><a [routerLink]="['/block/' | relativeUrl, block.id]" title="{{ block.id }}">{{ block.id | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="block.id"></app-clipboard></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Timestamp</td>
 | 
			
		||||
                <td i18n="block.timestamp">Timestamp</td>
 | 
			
		||||
                <td>
 | 
			
		||||
                  {{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}
 | 
			
		||||
                  <div class="lg-inline">
 | 
			
		||||
                    <i>(<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since> ago)</i>
 | 
			
		||||
                    <i>(<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since>)</i>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Size</td>
 | 
			
		||||
                <td i18n="block.size">Size</td>
 | 
			
		||||
                <td>{{ block.size | bytes: 2 }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Weight</td>
 | 
			
		||||
                <td i18n="block.weight">Weight</td>
 | 
			
		||||
                <td>{{ block.weight | wuBytes: 2 }}</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
@ -42,19 +42,19 @@
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr *ngIf="block.medianFee !== undefined">
 | 
			
		||||
                <td class="td-width">Median fee</td>
 | 
			
		||||
                <td>~{{ block.medianFee | number:'1.0-0' }} sat/vB (<app-fiat [value]="block.medianFee * 140" digitsInfo="1.2-2" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td>
 | 
			
		||||
                <td class="td-width" i18n="block.median-fee">Median fee</td>
 | 
			
		||||
                <td>~{{ block.medianFee | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="block.medianFee * 140" digitsInfo="1.2-2" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td>Total fees</td>
 | 
			
		||||
                  <td i18n="block.total-fees|Total fees in a block">Total fees</td>
 | 
			
		||||
                  <td *ngIf="network !== 'liquid'; else liquidTotalFees"><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> (<app-fiat [value]="fees * 100000000" digitsInfo="1.0-0"></app-fiat>)</td>
 | 
			
		||||
                  <ng-template #liquidTotalFees>
 | 
			
		||||
                    <td>{{ fees * 100000000 | number }} L-sat (<app-fiat [value]="fees * 100000000" digitsInfo="1.2-2"></app-fiat>)</td>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr *ngIf="network !== 'liquid'">
 | 
			
		||||
                  <td>Subsidy + fees:</td>
 | 
			
		||||
                  <td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <app-amount [satoshis]="(blockSubsidy + fees) * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> (<app-fiat [value]="(blockSubsidy + fees) * 100000000" digitsInfo="1.0-0"></app-fiat>)
 | 
			
		||||
                  </td>
 | 
			
		||||
@ -62,16 +62,16 @@
 | 
			
		||||
              </ng-template>
 | 
			
		||||
              <ng-template #loadingFees>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td>Total fees</td>
 | 
			
		||||
                  <td i18n="block.total-fees|Total fees in a block">Total fees</td>
 | 
			
		||||
                  <td style="width: 75%;"><span class="skeleton-loader"></span></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr *ngIf="network !== 'liquid'">
 | 
			
		||||
                  <td>Subsidy + fees:</td>
 | 
			
		||||
                  <td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
 | 
			
		||||
                  <td><span class="skeleton-loader"></span></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
              </ng-template>
 | 
			
		||||
              <tr>
 | 
			
		||||
                <td>Miner</td>
 | 
			
		||||
                <td i18n="block.miner">Miner</td>
 | 
			
		||||
                <td><app-miner [coinbaseTransaction]="coinbaseTx"></app-miner></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
@ -82,7 +82,7 @@
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2 class="float-left">{{ block.tx_count | number }} transaction<ng-template [ngIf]="block.tx_count !== 1">s</ng-template></h2>
 | 
			
		||||
    <h2 class="float-left">{{ block.tx_count | number }} <ng-template [ngIf]="block.tx_count === 1" i18n="shared.transaction-count.singular">transaction</ng-template><ng-template [ngIf]="block.tx_count !== 1" i18n="shared.transaction-count.plural">transactions</ng-template></h2>
 | 
			
		||||
 | 
			
		||||
    <ngb-pagination class="float-right" [collectionSize]="block.tx_count" [rotate]="true" [pageSize]="itemsPerPage" [(page)]="page" (pageChange)="pageChange(page)" [maxSize]="paginationMaxSize" [boundaryLinks]="true"></ngb-pagination>
 | 
			
		||||
 | 
			
		||||
@ -162,7 +162,7 @@
 | 
			
		||||
 | 
			
		||||
  <ng-template [ngIf]="error">
 | 
			
		||||
    <div class="text-center">
 | 
			
		||||
      Error loading block data.
 | 
			
		||||
      <span i18n="block.error.loading-block-data">Error loading block data.</span>
 | 
			
		||||
      <br><br>
 | 
			
		||||
      <i>{{ error.error }}</i>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -7,14 +7,14 @@
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="block-body">
 | 
			
		||||
        <div class="fees">
 | 
			
		||||
          ~{{ block.medianFee | number:'1.0-0' }} sat/vB
 | 
			
		||||
          ~{{ block.medianFee | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="fee-span">
 | 
			
		||||
          {{ block.feeRange[1] | number:'1.0-0' }} - {{ block.feeRange[block.feeRange.length - 1] | number:'1.0-0' }} sat/vB
 | 
			
		||||
          {{ block.feeRange[1] | number:'1.0-0' }} - {{ block.feeRange[block.feeRange.length - 1] | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="block-size">{{ block.size | bytes: 2 }}</div>
 | 
			
		||||
        <div class="transaction-count">{{ block.tx_count | number }} transaction<ng-template [ngIf]="block.tx_count !== 1">s</ng-template></div>
 | 
			
		||||
        <div class="time-difference"><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since> ago</div>
 | 
			
		||||
        <div class="transaction-count">{{ block.tx_count | number }} <ng-template [ngIf]="block.tx_count === 1" i18n="shared.transaction">transaction</ng-template><ng-template [ngIf]="block.tx_count !== 1" i18n="shared.transactions">transactions</ng-template></div>
 | 
			
		||||
        <div class="time-difference"><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
  </div>
 | 
			
		||||
  <div *ngIf="(isLoading$ | async) === true" class="position-container loading">
 | 
			
		||||
    <div class="loading-block">
 | 
			
		||||
      <h3>Waiting for blocks...</h3>
 | 
			
		||||
      <h3 i18n="blockchain.waiting-for-blocks|Loading text">Waiting for blocks...</h3>
 | 
			
		||||
      <div class="spinner-border text-light mt-2"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
@ -2,4 +2,4 @@
 | 
			
		||||
  <button #btn class="btn btn-sm btn-link pt-0" style="line-height: 0.9;" [attr.data-clipboard-text]="text"> 
 | 
			
		||||
    <img src="./resources/clippy.svg" width="13">
 | 
			
		||||
  </button>
 | 
			
		||||
</span>
 | 
			
		||||
</span>
 | 
			
		||||
 | 
			
		||||
@ -1,21 +1,21 @@
 | 
			
		||||
<table style="width: 100%;">
 | 
			
		||||
  <tr *ngIf="(isLoadingWebSocket$ | async) === false && (feeEstimations$ | async) as feeEstimations; else loadingFees">
 | 
			
		||||
    <td class="d-none d-md-block">
 | 
			
		||||
      <h5 class="card-title">Low priority</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="fees-box.low-priority">Low priority</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        {{ feeEstimations.hourFee }} sat/vB (<app-fiat [value]="feeEstimations.hourFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
 | 
			
		||||
        {{ feeEstimations.hourFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.hourFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
 | 
			
		||||
      </p>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      <h5 class="card-title">Medium priority</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="fees-box.medium-priority">Medium priority</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        {{ feeEstimations.halfHourFee }} sat/vB (<app-fiat [value]="feeEstimations.halfHourFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
 | 
			
		||||
        {{ feeEstimations.halfHourFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.halfHourFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
 | 
			
		||||
      </p>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      <h5 class="card-title">High priority</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="fees-box.high-priority">High priority</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        {{ feeEstimations.fastestFee }} sat/vB (<app-fiat [value]="feeEstimations.fastestFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
 | 
			
		||||
        {{ feeEstimations.fastestFee }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> (<app-fiat [value]="feeEstimations.fastestFee * 140" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)
 | 
			
		||||
      </p>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
@ -24,15 +24,15 @@
 | 
			
		||||
<ng-template #loadingFees>
 | 
			
		||||
  <tr>
 | 
			
		||||
    <td class="d-none d-md-block">
 | 
			
		||||
      <h5 class="card-title">Low priority</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="fees-box.low-priority">Low priority</h5>
 | 
			
		||||
      <p class="card-text"><span class="skeleton-loader"></span></p>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      <h5 class="card-title">Medium priority</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="fees-box.medium-priority">Medium priority</h5>
 | 
			
		||||
      <p class="card-text"><span class="skeleton-loader" style="width: 80%;"></span></p>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      <h5 class="card-title">High priority</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="fees-box.high-priority">High priority</h5>
 | 
			
		||||
      <p class="card-text"><span class="skeleton-loader"></span></p>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
 | 
			
		||||
@ -2,22 +2,22 @@
 | 
			
		||||
  <div class="container-xl">
 | 
			
		||||
    <div class="row text-center" *ngIf="mempoolInfoData$ | async as mempoolInfoData">
 | 
			
		||||
      <div class="col d-none d-sm-block">
 | 
			
		||||
        <span class="txPerSecond">Tx vBytes per second:</span>
 | 
			
		||||
        <span class="txPerSecond" i18n="footer.tx-vbytes-per-second">Tx vBytes per second:</span>
 | 
			
		||||
        <span *ngIf="mempoolInfoData.vBytesPerSecond === 0; else inSync">
 | 
			
		||||
           <span class="badge badge-pill badge-warning">Backend is synchronizing</span>
 | 
			
		||||
           <span class="badge badge-pill badge-warning" i18n="footer.backend-is-synchronizing">Backend is synchronizing</span>
 | 
			
		||||
        </span>
 | 
			
		||||
        <ng-template #inSync>
 | 
			
		||||
          <div class="progress sub-text">
 | 
			
		||||
            <div class="progress-bar {{ mempoolInfoData.progressClass }}" role="progressbar" [ngStyle]="{'width': mempoolInfoData.progressWidth}">{{ mempoolInfoData.vBytesPerSecond | ceil | number }} vBytes/s</div>
 | 
			
		||||
            <div class="progress-bar {{ mempoolInfoData.progressClass }}" role="progressbar" [ngStyle]="{'width': mempoolInfoData.progressWidth}">{{ mempoolInfoData.vBytesPerSecond | ceil | number }} <span i18n="shared.vbytes-per-second">vBytes/s</span></div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </ng-template>    
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col">
 | 
			
		||||
        <span class="unconfirmedTx">Unconfirmed<span class="extra-text"> transactions</span>:</span>
 | 
			
		||||
        <span class="unconfirmedTx"><span i18n="shared.unconfirmed">Unconfirmed</span> <span class="extra-text" i18n="shared.transactions">transactions</span>:</span>
 | 
			
		||||
        <div class="sub-text">{{ mempoolInfoData.memPoolInfo.size | number }}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col">
 | 
			
		||||
        <span class="mempoolSize">Mempool size:</span>
 | 
			
		||||
        <span class="mempoolSize" i18n="footer.mempool-size">Mempool size:</span>
 | 
			
		||||
        <div class="sub-text" *ngIf="(mempoolBlocksData$ | async) as mempoolBlocksData">{{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} block<span [hidden]="mempoolBlocksData.blocks <= 1">s</span>)</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -6,17 +6,17 @@
 | 
			
		||||
 | 
			
		||||
  <table class="table table-borderless" [alwaysCallback]="true" [fromRoot]="true" [infiniteScrollContainer]="'body'" infiniteScroll [infiniteScrollDistance]="1.5" [infiniteScrollUpDistance]="1.5" [infiniteScrollThrottle]="50" (scrolled)="loadMore()">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <th style="width: 15%;">Height</th>
 | 
			
		||||
      <th class="d-none d-md-block" style="width: 20%;">Timestamp</th>
 | 
			
		||||
      <th style="width: 20%;">Mined</th>
 | 
			
		||||
      <th class="d-none d-lg-block" style="width: 15%;">Transactions</th>
 | 
			
		||||
      <th style="width: 20%;">Filled</th>
 | 
			
		||||
      <th style="width: 15%;" i18n="latest-blocks.height">Height</th>
 | 
			
		||||
      <th class="d-none d-md-block" style="width: 20%;" i18n="latest-blocks.timestamp">Timestamp</th>
 | 
			
		||||
      <th style="width: 20%;" i18n="latest-blocks.mined">Mined</th>
 | 
			
		||||
      <th class="d-none d-lg-block" style="width: 15%;" i18n="latest-blocks.transactions">Transactions</th>
 | 
			
		||||
      <th style="width: 20%;" i18n="latest-blocks.filled">Filled</th>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody>
 | 
			
		||||
      <tr *ngFor="let block of blocks; let i= index; trackBy: trackByBlock">
 | 
			
		||||
        <td><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
 | 
			
		||||
        <td class="d-none d-md-block">{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}</td>
 | 
			
		||||
        <td><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since> ago</td>
 | 
			
		||||
        <td><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></td>
 | 
			
		||||
        <td class="d-none d-lg-block">{{ block.tx_count | number }}</td>
 | 
			
		||||
        <td>
 | 
			
		||||
          <div class="progress position-relative">
 | 
			
		||||
 | 
			
		||||
@ -4,8 +4,8 @@
 | 
			
		||||
  <a class="navbar-brand" [routerLink]="['/' | relativeUrl]" style="position: relative;">
 | 
			
		||||
    <ng-container *ngIf="{ val: connectionState$ | async } as connectionState">
 | 
			
		||||
      <img src="./resources/mempool-logo.png" height="35" width="140" class="logo" [ngStyle]="{'opacity': connectionState.val === 2 ? 1 : 0.5 }">
 | 
			
		||||
      <div class="badge badge-warning connection-badge" *ngIf="connectionState.val === 0">Offline</div>
 | 
			
		||||
      <div class="badge badge-warning connection-badge" style="left: 0px;" *ngIf="connectionState.val === 1">Reconnecting...</div>
 | 
			
		||||
      <div class="badge badge-warning connection-badge" *ngIf="connectionState.val === 0" i18n="master-page.offline">Offline</div>
 | 
			
		||||
      <div class="badge badge-warning connection-badge" style="left: 0px;" *ngIf="connectionState.val === 1" i18n="master-page.reconnecting">Reconnecting...</div>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
  </a>
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
    <div ngbDropdownMenu>
 | 
			
		||||
      <button ngbDropdownItem class="mainnet" routerLink="/"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</button>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</button>
 | 
			
		||||
      <h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header">Layer 2 Networks</h6>
 | 
			
		||||
      <h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="mainnet" [class.active]="network.val === 'bisq'" routerLink="/bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
 | 
			
		||||
      <button ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'" routerLink="/liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -13,23 +13,23 @@
 | 
			
		||||
        <table class="table table-borderless table-striped">
 | 
			
		||||
          <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td>Median fee</td>
 | 
			
		||||
              <td i18n="mempool-block.median-fee">Median fee</td>
 | 
			
		||||
              <td>~{{ mempoolBlock.medianFee | number:'1.0-0' }} sat/vB (<app-fiat [value]="mempoolBlock.medianFee * 140" digitsInfo="1.2-2" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat>)</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td>Fee span</td>
 | 
			
		||||
              <td i18n="mempool-block.fee-span">Fee span</td>
 | 
			
		||||
              <td><span class="yellow-color">{{ mempoolBlock.feeRange[0] | number:'1.0-0' }} - {{ mempoolBlock.feeRange[mempoolBlock.feeRange.length - 1] | number:'1.0-0' }} sat/vB</span></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td>Total fees</td>
 | 
			
		||||
              <td i18n="mempool-block.total-fees">Total fees</td>
 | 
			
		||||
              <td><app-amount [satoshis]="mempoolBlock.totalFees" [digitsInfo]="'1.2-2'" [noFiat]="true"></app-amount> (<app-fiat [value]="mempoolBlock.totalFees" digitsInfo="1.0-0"></app-fiat>)</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td>Transactions</td>
 | 
			
		||||
              <td i18n="mempool-block.transactions">Transactions</td>
 | 
			
		||||
              <td>{{ mempoolBlock.nTx }}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
              <td>Filled</td>
 | 
			
		||||
              <td i18n="mempool-block.filled">Filled</td>
 | 
			
		||||
              <td>
 | 
			
		||||
                <div class="progress position-relative">
 | 
			
		||||
                  <div class="progress-bar progress-mempool {{ (network$ | async) }}" role="progressbar" [ngStyle]="{'width': (mempoolBlock.blockVSize / 1000000) * 100 + '%' }"></div>
 | 
			
		||||
@ -48,4 +48,4 @@
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -5,23 +5,23 @@
 | 
			
		||||
        <a [routerLink]="['/mempool-block/' | relativeUrl, i]" class="blockLink"> </a>
 | 
			
		||||
        <div class="block-body">
 | 
			
		||||
          <div class="fees">
 | 
			
		||||
            ~{{ projectedBlock.medianFee | number:'1.0-0' }} sat/vB
 | 
			
		||||
            ~{{ projectedBlock.medianFee | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="fee-span">
 | 
			
		||||
            {{ projectedBlock.feeRange[0] | number:'1.0-0' }} - {{ projectedBlock.feeRange[projectedBlock.feeRange.length - 1] | number:'1.0-0' }} sat/vB
 | 
			
		||||
            {{ projectedBlock.feeRange[0] | number:'1.0-0' }} - {{ projectedBlock.feeRange[projectedBlock.feeRange.length - 1] | number:'1.0-0' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="block-size">{{ projectedBlock.blockSize | bytes: 2 }}</div>
 | 
			
		||||
          <div class="transaction-count">{{ projectedBlock.nTx | number }} transaction<ng-template [ngIf]="projectedBlock.nTx !== 1">s</ng-template></div>
 | 
			
		||||
          <div class="transaction-count">{{ projectedBlock.nTx | number }} <ng-template [ngIf]="projectedBlock.nTx === 1" i18n="shared.transaction-count.singular">transaction</ng-template><ng-template [ngIf]="projectedBlock.nTx !== 1" i18n="shared.transaction-count.plural">transactions</ng-template></div>
 | 
			
		||||
          <div class="time-difference" *ngIf="projectedBlock.blockVSize <= 1000000; else mergedBlock">
 | 
			
		||||
            <ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeDiffMainnet">
 | 
			
		||||
              In < {{ 1 * i + 1 }} minute
 | 
			
		||||
              <span i18n="mempool-blocks.eta-of-next-block|Block Frequency">In</span> < {{ 1 * i + 1 }} <span i18n="shared.minute">minute</span>
 | 
			
		||||
            </ng-template>
 | 
			
		||||
            <ng-template #timeDiffMainnet>
 | 
			
		||||
              In ~{{ 10 * i + 10 }} minutes
 | 
			
		||||
              <span i18n="mempool-blocks.eta-of-next-block|Block Frequency">In</span> ~{{ 10 * i + 10 }} <span i18n="shared.minutes">minutes</span>
 | 
			
		||||
            </ng-template>
 | 
			
		||||
          </div>
 | 
			
		||||
          <ng-template #mergedBlock>
 | 
			
		||||
            <div class="time-difference"><b>({{ projectedBlock.blockVSize / 1000000 | ceil }} blocks)</b></div>
 | 
			
		||||
            <div class="time-difference"><b>({{ projectedBlock.blockVSize / 1000000 | ceil }} <span i18n="shared.blocks">blocks</span>)</b></div>
 | 
			
		||||
          </ng-template>
 | 
			
		||||
        </div>
 | 
			
		||||
        <span class="animated-border"></span>
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,6 @@
 | 
			
		||||
    <a placement="bottom" [ngbTooltip]="title" [href]="url" target="_blank" class="badge badge-primary">{{ miner }}</a>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
  <ng-template #unknownMiner>
 | 
			
		||||
    <span class="badge badge-secondary">Unknown</span>
 | 
			
		||||
    <span class="badge badge-secondary" i18n="miner.tag.unknown-miner">Unknown</span>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
<form [formGroup]="searchForm" (submit)="searchForm.valid && search()" novalidate>
 | 
			
		||||
  <div class="d-flex">
 | 
			
		||||
    <div class="search-box-container mr-2">
 | 
			
		||||
      <input #instance="ngbTypeahead" [ngbTypeahead]="typeaheadSearch" (selectItem)="itemSelected()" (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" placeholder="TXID, block height, hash or address">
 | 
			
		||||
      <input #instance="ngbTypeahead" [ngbTypeahead]="typeaheadSearch" (selectItem)="itemSelected()" (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="TXID, block height, hash or address">
 | 
			
		||||
    </div>
 | 
			
		||||
    <div>
 | 
			
		||||
      <button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary"><fa-icon [icon]="['fas', 'search']" [fixedWidth]="true" title="Search"></fa-icon></button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</form>
 | 
			
		||||
</form>
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
  <div class="row">
 | 
			
		||||
    <div class="col-lg-12" *ngIf="loading">
 | 
			
		||||
      <div class="text-center">
 | 
			
		||||
        <h3>Loading graphs...</h3>
 | 
			
		||||
        <h3 i18n="statistics.loading-graphs">Loading graphs...</h3>
 | 
			
		||||
        <br>
 | 
			
		||||
        <div class="spinner-border text-light"></div>
 | 
			
		||||
      </div>
 | 
			
		||||
@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
      <div class="card mb-3" *ngIf="mempoolStats.length">
 | 
			
		||||
        <div class="card-header">
 | 
			
		||||
          <i class="fa fa-area-chart"></i> Mempool by vBytes (sat/vByte)
 | 
			
		||||
          <i class="fa fa-area-chart"></i> <span i18n="statistics.memory-by-vBytes">Mempool by vBytes (sat/vByte)</span>
 | 
			
		||||
 | 
			
		||||
          <form [formGroup]="radioGroupForm" style="float: right;">
 | 
			
		||||
            <div class="spinner-border text-light bootstrap-spinner" *ngIf="spinnerLoading"></div>
 | 
			
		||||
@ -54,7 +54,8 @@
 | 
			
		||||
    <div class="col-lg-12">
 | 
			
		||||
      <div class="card mb-3" *ngIf="mempoolTransactionsWeightPerSecondData">
 | 
			
		||||
        <div class="card-header">
 | 
			
		||||
          <i class="fa fa-area-chart"></i> Transaction vBytes per second (vB/s)</div>
 | 
			
		||||
            <i class="fa fa-area-chart"></i> <span i18n="statistics.transaction-vbytes-per-second">Transaction vBytes per second (vB/s)</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <div style="height: 600px;">
 | 
			
		||||
            <app-chartist
 | 
			
		||||
 | 
			
		||||
@ -18,4 +18,4 @@
 | 
			
		||||
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -18,17 +18,6 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
    private ref: ChangeDetectorRef,
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
  ) {
 | 
			
		||||
    if (document.body.clientWidth < 768) {
 | 
			
		||||
      this.intervals = {
 | 
			
		||||
        year: 31536000,
 | 
			
		||||
        month: 2592000,
 | 
			
		||||
        week: 604800,
 | 
			
		||||
        day: 86400,
 | 
			
		||||
        hour: 3600,
 | 
			
		||||
        min: 60,
 | 
			
		||||
        sec: 1
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      this.intervals = {
 | 
			
		||||
        year: 31536000,
 | 
			
		||||
        month: 2592000,
 | 
			
		||||
@ -38,7 +27,6 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
        minute: 60,
 | 
			
		||||
        second: 1
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
@ -65,7 +53,7 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
  calculate() {
 | 
			
		||||
    const seconds = Math.floor((+new Date() - +new Date(this.time * 1000)) / 1000);
 | 
			
		||||
    if (seconds < 60) {
 | 
			
		||||
      return '< 1 minute';
 | 
			
		||||
      return $localize`:@@time-since.just-now:Just now`;
 | 
			
		||||
    }
 | 
			
		||||
    let counter;
 | 
			
		||||
    for (const i in this.intervals) {
 | 
			
		||||
@ -73,9 +61,41 @@ export class TimeSinceComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
        counter = Math.floor(seconds / this.intervals[i]);
 | 
			
		||||
        if (counter > 0) {
 | 
			
		||||
          if (counter === 1) {
 | 
			
		||||
              return counter + ' ' + i; // singular (1 day ago)
 | 
			
		||||
            switch (i) { // singular (1 day ago)
 | 
			
		||||
              case 'year': return $localize`:@@time-since.year.ago:${counter}:INTERPOLATION: year ago`; break;
 | 
			
		||||
              case 'month': return $localize`:@@time-since.month.ago:${counter}:INTERPOLATION: month ago`; break;
 | 
			
		||||
              case 'week': return $localize`:@@time-since.week.ago:${counter}:INTERPOLATION: week ago`; break;
 | 
			
		||||
              case 'day': return $localize`:@@time-since.day.ago:${counter}:INTERPOLATION: day ago`; break;
 | 
			
		||||
              case 'hour': return $localize`:@@time-since.hour.ago:${counter}:INTERPOLATION: hour ago`; break;
 | 
			
		||||
              case 'minute':
 | 
			
		||||
                if (document.body.clientWidth < 768) {
 | 
			
		||||
                  return $localize`:@@time-since.min.ago:${counter}:INTERPOLATION: min ago`;
 | 
			
		||||
                }
 | 
			
		||||
                return $localize`:@@time-since.minute.ago:${counter}:INTERPOLATION: minute ago`;
 | 
			
		||||
              case 'second':
 | 
			
		||||
                if (document.body.clientWidth < 768) {
 | 
			
		||||
                  return $localize`:@@time-since.sec.ago:${counter}:INTERPOLATION: sec ago`;
 | 
			
		||||
                }
 | 
			
		||||
                return $localize`:@@time-since.second.ago:${counter}:INTERPOLATION: second ago`;
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
              return counter + ' ' + i + 's'; // plural (2 days ago)
 | 
			
		||||
            switch (i) { // plural (2 days ago)
 | 
			
		||||
              case 'year': return $localize`:@@time-since.years.ago:${counter}:INTERPOLATION: years ago`; break;
 | 
			
		||||
              case 'month': return $localize`:@@time-since.months.ago:${counter}:INTERPOLATION: months ago`; break;
 | 
			
		||||
              case 'week': return $localize`:@@time-since.weeks.ago:${counter}:INTERPOLATION: weeks ago`; break;
 | 
			
		||||
              case 'day': return $localize`:@@time-since.days.ago:${counter}:INTERPOLATION: days ago`; break;
 | 
			
		||||
              case 'hour': return $localize`:@@time-since.hours.ago:${counter}:INTERPOLATION: hours ago`; break;
 | 
			
		||||
              case 'minute':
 | 
			
		||||
                if (document.body.clientWidth < 768) {
 | 
			
		||||
                  return $localize`:@@time-since.mins.ago:${counter}:INTERPOLATION: mins ago`;
 | 
			
		||||
                }
 | 
			
		||||
                return $localize`:@@time-since.minutes.ago:${counter}:INTERPOLATION: minutes ago`;
 | 
			
		||||
              case 'second':
 | 
			
		||||
                if (document.body.clientWidth < 768) {
 | 
			
		||||
                  return $localize`:@@time-since.secs.ago:${counter}:INTERPOLATION: secs ago`;
 | 
			
		||||
                }
 | 
			
		||||
                return $localize`:@@time-since.seconds.ago:${counter}:INTERPOLATION: seconds ago`;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,8 @@ export class TimespanComponent implements OnChanges {
 | 
			
		||||
  ngOnChanges() {
 | 
			
		||||
    const seconds = this.time;
 | 
			
		||||
    if (seconds < 60) {
 | 
			
		||||
      return '< 1 minute';
 | 
			
		||||
      this.text = '< 1 minute';
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const intervals = {
 | 
			
		||||
        year: 31536000,
 | 
			
		||||
 | 
			
		||||
@ -2,20 +2,20 @@
 | 
			
		||||
 | 
			
		||||
  <div class="title-block">
 | 
			
		||||
    <div *ngIf="rbfTransaction" class="alert alert-mempool" role="alert">
 | 
			
		||||
      This transaction has been replaced by:
 | 
			
		||||
      <span i18n="transaction.rbf.replacement|RBF replacement">This transaction has been replaced by:</span>
 | 
			
		||||
      <a class="alert-link" [routerLink]="['/tx/' | relativeUrl, rbfTransaction.txid]" [state]="{ data: rbfTransaction }">
 | 
			
		||||
        <span class="d-inline d-lg-none">{{ rbfTransaction.txid | shortenString : 24 }}</span>
 | 
			
		||||
        <span class="d-none d-lg-inline">{{ rbfTransaction.txid }}</span>
 | 
			
		||||
      </a>
 | 
			
		||||
    </div>
 | 
			
		||||
  
 | 
			
		||||
    <h1 class="float-left mr-3 mb-md-3">Transaction</h1>
 | 
			
		||||
    <h1 class="float-left mr-3 mb-md-3" i18n="shared.transaction">Transaction</h1>
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="tx?.status?.confirmed">
 | 
			
		||||
      <button *ngIf="latestBlock" type="button" class="btn btn-sm btn-success float-right mr-2 mt-1 mt-md-3">{{ latestBlock.height - tx.status.block_height + 1 }} confirmation<ng-container *ngIf="latestBlock.height - tx.status.block_height + 1 > 1">s</ng-container></button>
 | 
			
		||||
      <button *ngIf="latestBlock" type="button" class="btn btn-sm btn-success float-right mr-2 mt-1 mt-md-3">{{ latestBlock.height - tx.status.block_height + 1 }} <ng-container *ngIf="latestBlock.height - tx.status.block_height + 1 == 1" i18n="shared.confirmation-count.singular|Transaction singular confirmation count">confirmation</ng-container><ng-container *ngIf="latestBlock.height - tx.status.block_height + 1 > 1" i18n="shared.confirmation-count.plural|Transaction plural confirmation count">confirmations</ng-container></button>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
    <ng-template [ngIf]="tx && !tx?.status.confirmed">
 | 
			
		||||
      <button type="button" class="btn btn-sm btn-danger float-right mr-2 mt-1 mt-md-3">Unconfirmed</button>
 | 
			
		||||
      <button type="button" class="btn btn-sm btn-danger float-right mr-2 mt-1 mt-md-3" i18n="transaction.unconfirmed|Transaction unconfirmed state">Unconfirmed</button>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
 | 
			
		||||
    <div>
 | 
			
		||||
@ -39,28 +39,28 @@
 | 
			
		||||
            <table class="table table-borderless table-striped">
 | 
			
		||||
              <tbody>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td>Timestamp</td>
 | 
			
		||||
                  <td i18n="transaction.timestamp|Transaction Timestamp">Timestamp</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    {{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}
 | 
			
		||||
                    <div class="lg-inline">
 | 
			
		||||
                      <i>(<app-time-since [time]="tx.status.block_time" [fastRender]="true"></app-time-since> ago)</i>
 | 
			
		||||
                      <i>(<app-time-since [time]="tx.status.block_time" [fastRender]="true"></app-time-since>)</i>
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr *ngIf="latestBlock && tx.status.block_height <= latestBlock.height - 8">
 | 
			
		||||
                  <td class="td-width">Included in block</td>
 | 
			
		||||
                  <td class="td-width" i18n="transaction.included-in-block|Transaction included in block">Included in block</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <a [routerLink]="['/block/' | relativeUrl, tx.status.block_hash]" [state]="{ data: { blockHeight: tx.status.block_height } }">{{ tx.status.block_height }}</a>
 | 
			
		||||
                  </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <ng-template [ngIf]="transactionTime > 0">
 | 
			
		||||
                  <tr>
 | 
			
		||||
                    <td>Confirmed</td>
 | 
			
		||||
                    <td>After <app-timespan [time]="tx.status.block_time - transactionTime"></app-timespan></td>
 | 
			
		||||
                    <td i18n="transaction.confirmed|Transaction Confirmed state">Confirmed</td>
 | 
			
		||||
                    <td><span i18n="transaction.confirmed.after|Transaction confirmed after">After</span> <app-timespan [time]="tx.status.block_time - transactionTime"></app-timespan></td>
 | 
			
		||||
                  </tr>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <tr *ngIf="network !== 'liquid'">
 | 
			
		||||
                  <td class="td-width">Features</td>
 | 
			
		||||
                  <td class="td-width" i18n="transaction.features|Transaction features">Features</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <app-tx-features [tx]="tx"></app-tx-features>
 | 
			
		||||
                  </td>
 | 
			
		||||
@ -72,13 +72,13 @@
 | 
			
		||||
            <table class="table table-borderless table-striped">
 | 
			
		||||
              <tbody>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td class="td-width">Fee</td>
 | 
			
		||||
                  <td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td>
 | 
			
		||||
                  <td>{{ tx.fee | number }} sat (<app-fiat [value]="tx.fee"></app-fiat>)</td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td>Fee per vByte</td>
 | 
			
		||||
                  <td i18n="transaction.fee-per-vbyte|Transaction fee">Fee per vByte</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB
 | 
			
		||||
                    {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
 | 
			
		||||
                     
 | 
			
		||||
                    <app-tx-fee-rating *ngIf="tx.fee" [tx]="tx"></app-tx-fee-rating>
 | 
			
		||||
                  </td>
 | 
			
		||||
@ -106,35 +106,34 @@
 | 
			
		||||
                  </tr>
 | 
			
		||||
                  <ng-template #firstSeenTmpl>
 | 
			
		||||
                    <tr>
 | 
			
		||||
                      <td>First seen</td>
 | 
			
		||||
                      <td><i><app-time-since [time]="transactionTime" [fastRender]="true"></app-time-since> ago</i></td>
 | 
			
		||||
                      <td i18n="transaction.first-seen|Transaction first seen">First seen</td>
 | 
			
		||||
                      <td><i><app-time-since [time]="transactionTime" [fastRender]="true"></app-time-since></i></td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                  </ng-template>
 | 
			
		||||
                </ng-template>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td class="td-width">ETA</td>
 | 
			
		||||
                  <td class="td-width" i18n="transaction.eta|Transaction ETA">ETA</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <ng-template [ngIf]="txInBlockIndex === undefined" [ngIfElse]="estimationTmpl">
 | 
			
		||||
                      <span class="skeleton-loader"></span>
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                    <ng-template #estimationTmpl>
 | 
			
		||||
                      <ng-template [ngIf]="txInBlockIndex >= 7" [ngIfElse]="belowBlockLimit">
 | 
			
		||||
                        In several hours (or more)
 | 
			
		||||
                        <span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
 | 
			
		||||
                      </ng-template>
 | 
			
		||||
                      <ng-template #belowBlockLimit>
 | 
			
		||||
                        <ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeEstimateDefault">
 | 
			
		||||
                          < {{ 1 * txInBlockIndex + 1 }} minutes <i>({{ txInBlockIndex + 1 }} block{{ txInBlockIndex > 0 ? 's' : '' }})</i>
 | 
			
		||||
                          < {{ 1 * txInBlockIndex + 1 }} <span i18n="transaction.minutes|Transaction Minutes">minutes</span> <i>({{ txInBlockIndex + 1 }} <span i18n="transaction.eta.block|Transaction ETA (X blocks)">block</span>{{ txInBlockIndex > 0 ? 's' : '' }})</i>
 | 
			
		||||
                        </ng-template>
 | 
			
		||||
                        <ng-template #timeEstimateDefault>
 | 
			
		||||
 | 
			
		||||
                          ~{{ 10 * txInBlockIndex + 10 }} minutes <i>({{ txInBlockIndex + 1 }} block{{ txInBlockIndex > 0 ? 's' : '' }})</i>
 | 
			
		||||
                          ~{{ 10 * txInBlockIndex + 10 }} <span i18n="transaction.minutes|Transaction Minutes">minutes</span> <i>({{ txInBlockIndex + 1 }} <span i18n="transaction.eta.block|Transaction ETA (X blocks)">block</span>{{ txInBlockIndex > 0 ? 's' : '' }})</i>
 | 
			
		||||
                        </ng-template>
 | 
			
		||||
                      </ng-template>
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                  </td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr *ngIf="network !== 'liquid'">
 | 
			
		||||
                  <td class="td-width">Features</td>
 | 
			
		||||
                  <td class="td-width" i18n="transaction.features|Transaction Features">Features</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <app-tx-features [tx]="tx"></app-tx-features>
 | 
			
		||||
                  </td>
 | 
			
		||||
@ -146,12 +145,12 @@
 | 
			
		||||
            <table class="table table-borderless table-striped">
 | 
			
		||||
              <tbody>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td class="td-width">Fee</td>
 | 
			
		||||
                  <td>{{ tx.fee | number }} sat (<app-fiat [value]="tx.fee"></app-fiat>)</td>
 | 
			
		||||
                  <td class="td-width" i18n="transaction.fee|Transaction Fee">Fee</td>
 | 
			
		||||
                  <td>{{ tx.fee | number }} <span i18n="transaction.fee.sat|Transaction Fee sat">sat</span> (<app-fiat [value]="tx.fee"></app-fiat>)</td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <tr>
 | 
			
		||||
                  <td>Fee per vByte</td>
 | 
			
		||||
                  <td>{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB</td>
 | 
			
		||||
                  <td i18n="transaction.fee-per-vbyte|Transaction fee">Fee per vByte</td>
 | 
			
		||||
                  <td>{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
              </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
@ -162,24 +161,24 @@
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
    <h2 class="float-left">Inputs & Outputs</h2>
 | 
			
		||||
    <h2 class="float-left" i18n="transaction.inputs-and-outputs|Transaction inputs and outputs">Inputs & Outputs</h2>
 | 
			
		||||
 | 
			
		||||
    <button type="button" class="btn btn-outline-info btn-sm float-right mr-1 mt-0 mt-md-2" (click)="txList.toggleDetails()">Details</button>
 | 
			
		||||
    <button type="button" class="btn btn-outline-info btn-sm float-right mr-1 mt-0 mt-md-2" (click)="txList.toggleDetails()" i18n="transaction.details|Transaction Details">Details</button>
 | 
			
		||||
 | 
			
		||||
    <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
    <app-transactions-list #txList [transactions]="[tx]" [transactionPage]="true"></app-transactions-list>
 | 
			
		||||
 | 
			
		||||
    <h2>Details</h2>
 | 
			
		||||
    <h2 i18n="transaction.details">Details</h2>
 | 
			
		||||
    <div class="box">
 | 
			
		||||
      <table class="table table-borderless table-striped">
 | 
			
		||||
        <tbody>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td>Size</td>
 | 
			
		||||
            <td i18n="transaction.size|Transaction Size">Size</td>
 | 
			
		||||
            <td>{{ tx.size | bytes: 2 }}</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <td>Weight</td>
 | 
			
		||||
            <td i18n="transaction.weight|Transaction Weight">Weight</td>
 | 
			
		||||
            <td>{{ tx.weight | wuBytes: 2 }}</td>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
@ -263,8 +262,8 @@
 | 
			
		||||
  <ng-template [ngIf]="error">
 | 
			
		||||
 | 
			
		||||
    <div class="text-center" *ngIf="waitingForTransaction; else errorTemplate">
 | 
			
		||||
      <h3>Transaction not found.</h3>
 | 
			
		||||
      <h5>Waiting for it to appear in the mempool...</h5>
 | 
			
		||||
      <h3 i18n="transaction.error.transaction-not-found">Transaction not found.</h3>
 | 
			
		||||
      <h5 i18n="transaction.error.waiting-for-it-to-appear">Waiting for it to appear in the mempool...</h5>
 | 
			
		||||
      <div class="spinner-border text-light mt-2"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
    <div class="float-right">
 | 
			
		||||
      <ng-template [ngIf]="tx.status.confirmed">{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-template>
 | 
			
		||||
      <ng-template [ngIf]="!tx.status.confirmed && tx.firstSeen">
 | 
			
		||||
        <i><app-time-since [time]="tx.firstSeen" [fastRender]="true"></app-time-since> ago</i>
 | 
			
		||||
        <i><app-time-since [time]="tx.firstSeen" [fastRender]="true"></app-time-since></i>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="clearfix"></div>
 | 
			
		||||
@ -36,9 +36,9 @@
 | 
			
		||||
                </td>
 | 
			
		||||
                <td>
 | 
			
		||||
                  <div [ngSwitch]="true">
 | 
			
		||||
                    <ng-container *ngSwitchCase="vin.is_coinbase"><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii">Coinbase<ng-template [ngIf]="network !== 'liquid'"> (Newly Generated Coins)</ng-template></a><br><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></ng-container>
 | 
			
		||||
                    <ng-container *ngSwitchCase="vin.is_coinbase"><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii"><span i18n="transactions-list.coinbase">Coinbase</span><ng-template [ngIf]="network !== 'liquid'"> <span i18n="transactions-list.newly-generated-coins">(Newly Generated Coins)</span></ng-template></a><br><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></ng-container>
 | 
			
		||||
                    <ng-container *ngSwitchCase="vin.is_pegin">
 | 
			
		||||
                      Peg-in
 | 
			
		||||
                      <span i18n="transactions-list.peg-in">Peg-in</span>
 | 
			
		||||
                    </ng-container>
 | 
			
		||||
                    <ng-container *ngSwitchDefault>
 | 
			
		||||
                      <a [routerLink]="['/address/' | relativeUrl, vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
 | 
			
		||||
@ -68,32 +68,32 @@
 | 
			
		||||
                    <tbody>
 | 
			
		||||
                      <ng-template [ngIf]="vin.scriptsig">
 | 
			
		||||
                        <tr>
 | 
			
		||||
                          <td>ScriptSig (ASM)</td>
 | 
			
		||||
                          <td i18n="transactions-list.scriptsig.asm|ScriptSig (ASM)">ScriptSig (ASM)</td>
 | 
			
		||||
                          <td [innerHTML]="vin.scriptsig_asm | asmStyler"></td>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                        <tr>
 | 
			
		||||
                          <td>ScriptSig (HEX)</td>
 | 
			
		||||
                          <td i18n="transactions-list.scriptsig.hex|ScriptSig (HEX)">ScriptSig (HEX)</td>
 | 
			
		||||
                          <td>{{ vin.scriptsig }}</td>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                      </ng-template>
 | 
			
		||||
                      <tr *ngIf="vin.witness">
 | 
			
		||||
                        <td>Witness</td>
 | 
			
		||||
                        <td i18n="transactions-list.witness">Witness</td>
 | 
			
		||||
                        <td>{{ vin.witness.join(' ') }}</td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr *ngIf="vin.inner_redeemscript_asm">
 | 
			
		||||
                        <td>P2SH redeem script</td>
 | 
			
		||||
                        <td i18n="transactions-list.p2sh-redeem-script">P2SH redeem script</td>
 | 
			
		||||
                        <td [innerHTML]="vin.inner_redeemscript_asm | asmStyler"></td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr *ngIf="vin.inner_witnessscript_asm">
 | 
			
		||||
                        <td>P2WSH witness script</td>
 | 
			
		||||
                        <td i18n="transactions-list.p2wsh-witness-script">P2WSH witness script</td>
 | 
			
		||||
                        <td [innerHTML]="vin.inner_witnessscript_asm | asmStyler"></td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr>
 | 
			
		||||
                        <td>nSequence</td>
 | 
			
		||||
                        <td i18n="transactions-list.nsequence">nSequence</td>
 | 
			
		||||
                        <td>{{ formatHex(vin.sequence) }}</td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr *ngIf="vin.prevout">
 | 
			
		||||
                        <td>Previous output script</td>
 | 
			
		||||
                        <td i18n="transactions-list.previous-output-script">Previous output script</td>
 | 
			
		||||
                        <td [innerHTML]="vin.prevout.scriptpubkey_asm | asmStyler">{{ vin.prevout.scriptpubkey_type ? ('(' + vin.prevout.scriptpubkey_type + ')') : '' }}"</td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                    </tbody>
 | 
			
		||||
@ -103,7 +103,7 @@
 | 
			
		||||
            </ng-template>
 | 
			
		||||
            <tr *ngIf="tx.vin.length > 10 && tx['@vinLimit']">
 | 
			
		||||
              <td colspan="3" class="text-center">
 | 
			
		||||
                <button class="btn btn-sm btn-primary mt-2" (click)="tx['@vinLimit'] = false;">Load all ({{ tx.vin.length - 10 }})</button>
 | 
			
		||||
                <button class="btn btn-sm btn-primary mt-2" (click)="tx['@vinLimit'] = false;"><span i18n="transactions-list.load-all">Load all</span> ({{ tx.vin.length - 10 }})</button>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
@ -122,7 +122,8 @@
 | 
			
		||||
                  </a>
 | 
			
		||||
                  <ng-template #scriptpubkey_type>
 | 
			
		||||
                    <ng-template [ngIf]="vout.pegout" [ngIfElse]="defaultscriptpubkey_type">
 | 
			
		||||
                      Peg-out to <a [routerLink]="['/address/', vout.pegout.scriptpubkey_address]" title="{{ vout.pegout.scriptpubkey_address }}">
 | 
			
		||||
                      <span i18n="transactions-list.peg-out-to">Peg-out to</span>
 | 
			
		||||
                      <a [routerLink]="['/address/', vout.pegout.scriptpubkey_address]" title="{{ vout.pegout.scriptpubkey_address }}">
 | 
			
		||||
                        <span class="d-block d-lg-none">{{ vout.pegout.scriptpubkey_address | shortenString : 16 }}</span>
 | 
			
		||||
                        <span class="d-none d-lg-block">{{ vout.pegout.scriptpubkey_address | shortenString : 35 }}</span>
 | 
			
		||||
                      </a>
 | 
			
		||||
@ -160,19 +161,19 @@
 | 
			
		||||
                  <table class="table table-striped table-borderless details-table mb-3">
 | 
			
		||||
                    <tbody>
 | 
			
		||||
                      <tr *ngIf="vout.scriptpubkey_type">
 | 
			
		||||
                        <td>Type</td>
 | 
			
		||||
                        <td i18n="transactions-list.vout.scriptpubkey-type">Type</td>
 | 
			
		||||
                        <td>{{ vout.scriptpubkey_type.toUpperCase() }}</td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr>
 | 
			
		||||
                        <td>scriptPubKey (ASM)</td>
 | 
			
		||||
                        <td i18n="transactions-list.scriptpubkey.asm|ScriptPubKey (ASM)">ScriptPubKey (ASM)</td>
 | 
			
		||||
                        <td [innerHTML]="vout.scriptpubkey_asm | asmStyler"></td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr>
 | 
			
		||||
                        <td>scriptPubKey (HEX)</td>
 | 
			
		||||
                        <td i18n="transactions-list.scriptpubkey.hex|ScriptPubKey (HEX)">ScriptPubKey (HEX)</td>
 | 
			
		||||
                        <td>{{ vout.scriptpubkey }}</td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                      <tr *ngIf="vout.scriptpubkey_type == 'op_return'">
 | 
			
		||||
                        <td>OP_RETURN data</td>
 | 
			
		||||
                        <td>OP_RETURN <span i18n="transactions-list.vout.scriptpubkey-type.data">data</span></td>
 | 
			
		||||
                        <td>{{ vout.scriptpubkey_asm | hex2ascii }}</td>
 | 
			
		||||
                      </tr>
 | 
			
		||||
                    </tbody>
 | 
			
		||||
@ -182,7 +183,7 @@
 | 
			
		||||
            </ng-template>
 | 
			
		||||
            <tr *ngIf="tx.vout.length > 10 && tx['@voutLimit']">
 | 
			
		||||
              <td colspan="3" class="text-center">
 | 
			
		||||
                <button class="btn btn-sm btn-primary mt-2" (click)="tx['@voutLimit'] = false;">Load all ({{ tx.vout.length - 10 }})</button>
 | 
			
		||||
                <button class="btn btn-sm btn-primary mt-2" (click)="tx['@voutLimit'] = false;"><span i18n="transactions-list.load-all">Load all</span> ({{ tx.vout.length - 10 }})</button>
 | 
			
		||||
              </td>
 | 
			
		||||
            </tr>
 | 
			
		||||
          </tbody>
 | 
			
		||||
@ -192,19 +193,19 @@
 | 
			
		||||
 | 
			
		||||
    <div>
 | 
			
		||||
      <div class="float-left mt-2-5" *ngIf="!transactionPage && tx.fee">
 | 
			
		||||
        {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB <span class="d-none d-sm-inline-block"> – {{ tx.fee | number }} sat (<app-fiat [value]="tx.fee"></app-fiat>)</span>
 | 
			
		||||
        {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span> <span class="d-none d-sm-inline-block"> – {{ tx.fee | number }} <span i18n="shared.sat|sat">sat</span> (<app-fiat [value]="tx.fee"></app-fiat>)</span>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="float-right">
 | 
			
		||||
        <span *ngIf="showConfirmations && latestBlock$ | async as latestBlock">
 | 
			
		||||
          <button *ngIf="tx.status.confirmed; else unconfirmedButton" type="button" class="btn btn-sm btn-success mt-2">{{ latestBlock.height - tx.status.block_height + 1 }} confirmation<ng-container *ngIf="latestBlock.height - tx.status.block_height + 1 > 1">s</ng-container></button>
 | 
			
		||||
          <button *ngIf="tx.status.confirmed; else unconfirmedButton" type="button" class="btn btn-sm btn-success mt-2">{{ latestBlock.height - tx.status.block_height + 1 }} <ng-container *ngIf="latestBlock.height - tx.status.block_height + 1 == 1" i18n="shared.confirmation-count.singular">confirmation</ng-container><ng-container *ngIf="latestBlock.height - tx.status.block_height + 1 > 1" i18n="shared.confirmation-count.plural">confirmations</ng-container></button>
 | 
			
		||||
          <ng-template #unconfirmedButton>
 | 
			
		||||
            <button type="button" class="btn btn-sm btn-danger mt-2">Unconfirmed</button>
 | 
			
		||||
            <button type="button" class="btn btn-sm btn-danger mt-2" i18n="transactions-list.unconfirmed">Unconfirmed</button>
 | 
			
		||||
          </ng-template>
 | 
			
		||||
           
 | 
			
		||||
        </span>
 | 
			
		||||
        <button type="button" class="btn btn-sm btn-primary mt-2" (click)="switchCurrency()">
 | 
			
		||||
          <ng-template [ngIf]="network === 'liquid'" [ngIfElse]="defaultAmount">Confidential</ng-template>
 | 
			
		||||
          <ng-template [ngIf]="network === 'liquid'" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
 | 
			
		||||
          <ng-template #defaultAmount>
 | 
			
		||||
            <app-amount [satoshis]="getTotalTxOutput(tx)"></app-amount>
 | 
			
		||||
          </ng-template>
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
<!-- this component is only used for the angular string extractor -->{{counter}} 
 | 
			
		||||
<div>
 | 
			
		||||
  <span i18n="@@time-since.just-now">Just now</span>
 | 
			
		||||
  <span i18n="@@time-since.sec.ago">{{counter}} sec ago</span>
 | 
			
		||||
  <span i18n="@@time-since.secs.ago">{{counter}} secs ago</span>
 | 
			
		||||
  <span i18n="@@time-since.second.ago">{{counter}} second ago</span>
 | 
			
		||||
  <span i18n="@@time-since.seconds.ago">{{counter}} seconds ago</span>
 | 
			
		||||
  <span i18n="@@time-since.min.ago">{{counter}} min ago</span>
 | 
			
		||||
  <span i18n="@@time-since.mins.ago">{{counter}} mins ago</span>
 | 
			
		||||
  <span i18n="@@time-since.minute.ago">{{counter}} minute ago</span>
 | 
			
		||||
  <span i18n="@@time-since.minutes.ago">{{counter}} minutes ago</span>
 | 
			
		||||
  <span i18n="@@time-since.hour.ago">{{counter}} hour ago</span>
 | 
			
		||||
  <span i18n="@@time-since.hours.ago">{{counter}} hours ago</span>
 | 
			
		||||
  <span i18n="@@time-since.day.ago">{{counter}} day ago</span>
 | 
			
		||||
  <span i18n="@@time-since.days.ago">{{counter}} days ago</span>
 | 
			
		||||
  <span i18n="@@time-since.week.ago">{{counter}} week ago</span>
 | 
			
		||||
  <span i18n="@@time-since.weeks.ago">{{counter}} weeks ago</span>
 | 
			
		||||
  <span i18n="@@time-since.month.ago">{{counter}} month ago</span>
 | 
			
		||||
  <span i18n="@@time-since.months.ago">{{counter}} months ago</span>
 | 
			
		||||
  <span i18n="@@time-since.year.ago">{{counter}} year ago</span>
 | 
			
		||||
  <span i18n="@@time-since.years.ago">{{counter}} years ago</span>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
import { Component } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-translation-strings',
 | 
			
		||||
  templateUrl: './translation-strings.component.html'
 | 
			
		||||
})
 | 
			
		||||
export class TranslationStringsComponent {
 | 
			
		||||
  counter: string;
 | 
			
		||||
  constructor() { }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
<span *ngIf="segwitGains.realizedGains && !segwitGains.potentialBech32Gains; else segwitTwo" class="badge badge-success mr-1" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number:  '1.0-0' }}% on fees by using native SegWit-Bech32" placement="bottom">SegWit</span>
 | 
			
		||||
<span *ngIf="segwitGains.realizedGains && !segwitGains.potentialBech32Gains; else segwitTwo" class="badge badge-success mr-1" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number:  '1.0-0' }}% on fees by using native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
 | 
			
		||||
<ng-template #segwitTwo>
 | 
			
		||||
  <span *ngIf="segwitGains.realizedGains && segwitGains.potentialBech32Gains else potentialP2shGains" class="badge badge-warning mr-1" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number:  '1.0-0' }}% on fees by using SegWit and could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% more by fully upgrading to native SegWit-Bech32" placement="bottom">SegWit</span>
 | 
			
		||||
  <span *ngIf="segwitGains.realizedGains && segwitGains.potentialBech32Gains else potentialP2shGains" class="badge badge-warning mr-1" ngbTooltip="This transaction saved {{ segwitGains.realizedGains * 100 | number:  '1.0-0' }}% on fees by using SegWit and could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% more by fully upgrading to native SegWit-Bech32" placement="bottom" i18n="tx-features.tag.segwit|SegWit">SegWit</span>
 | 
			
		||||
  <ng-template #potentialP2shGains>
 | 
			
		||||
    <span *ngIf="segwitGains.potentialP2shGains" class="badge badge-danger mr-1" ngbTooltip="This transaction could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% on fees by upgrading to native SegWit-Bech32 or {{ segwitGains.potentialP2shGains * 100 | number:  '1.0-0' }}% by upgrading to SegWit-P2SH" placement="bottom"><del>SegWit</del></span>
 | 
			
		||||
    <span *ngIf="segwitGains.potentialP2shGains" class="badge badge-danger mr-1" ngbTooltip="This transaction could save {{ segwitGains.potentialBech32Gains * 100 | number : '1.0-0' }}% on fees by upgrading to native SegWit-Bech32 or {{ segwitGains.potentialP2shGains * 100 | number:  '1.0-0' }}% by upgrading to SegWit-P2SH" placement="bottom"><del i18n="tx-features.tag.segwit|SegWit">SegWit</del></span>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
</ng-template>
 | 
			
		||||
<span *ngIf="isRbfTransaction" class="badge badge-success" ngbTooltip="This transaction support Replace-By-Fee (RBF) allowing fee bumping" placement="bottom">RBF</span>
 | 
			
		||||
<span *ngIf="isRbfTransaction" class="badge badge-success" ngbTooltip="This transaction support Replace-By-Fee (RBF) allowing fee bumping" placement="bottom" i18n="tx-features.tag.rbf|RBF">RBF</span>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,3 @@
 | 
			
		||||
<span *ngIf="feeRating === 1" class="badge badge-success">Optimal</span>
 | 
			
		||||
<span *ngIf="feeRating === 2" class="badge badge-warning" title="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block">Overpaid {{ overpaidTimes }}x</span>
 | 
			
		||||
<span *ngIf="feeRating === 3" class="badge badge-danger" title="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block">Overpaid {{ overpaidTimes }}x</span>
 | 
			
		||||
<span *ngIf="feeRating === 1" class="badge badge-success" i18n="tx-fee-rating.optimal|TX Fee Rating is Optimal">Optimal</span>
 | 
			
		||||
<span *ngIf="feeRating === 2" class="badge badge-warning" title="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block" i18n="tx-fee-rating.overpaid.warning|TX Fee Rating is Warning">Overpaid {{ overpaidTimes }}x</span>
 | 
			
		||||
<span *ngIf="feeRating === 3" class="badge badge-danger" title="Only ~{{ medianFeeNeeded }} sat/vB was needed to get into this block" i18n="tx-fee-rating.overpaid.danger|TX Fee Rating is Danger">Overpaid {{ overpaidTimes }}x</span>
 | 
			
		||||
 | 
			
		||||
@ -72,18 +72,18 @@
 | 
			
		||||
      <div class="col mb-4">
 | 
			
		||||
        <div class="card text-center">
 | 
			
		||||
          <div class="card-body">
 | 
			
		||||
            <h5 class="card-title">Latest blocks</h5>
 | 
			
		||||
            <h5 class="card-title" i18n="dashboard.latest-blocks">Latest blocks</h5>
 | 
			
		||||
            <table class="table table-borderless text-left">
 | 
			
		||||
              <thead>
 | 
			
		||||
                <th style="width: 15%;">Height</th>
 | 
			
		||||
                <th style="width: 35%;">Mined</th>
 | 
			
		||||
                <th style="width: 20%;" class="d-none d-lg-table-cell">Txs</th>
 | 
			
		||||
                <th style="width: 30%;">Filled</th>
 | 
			
		||||
                <th style="width: 15%;" i18n="dashboard.latest-blocks.height">Height</th>
 | 
			
		||||
                <th style="width: 35%;" i18n="dashboard.latest-blocks.mined">Mined</th>
 | 
			
		||||
                <th style="width: 20%;" class="d-none d-lg-table-cell" i18n="dashboard.latest-blocks.transaction-count">TXs</th>
 | 
			
		||||
                <th style="width: 30%;" i18n="dashboard.latest-blocks.size">Size</th>
 | 
			
		||||
              </thead>
 | 
			
		||||
              <tbody>
 | 
			
		||||
                <tr *ngFor="let block of blocks$ | async; let i = index; trackBy: trackByBlock">
 | 
			
		||||
                  <td><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
 | 
			
		||||
                  <td><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since> ago</td>
 | 
			
		||||
                  <td><app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></td>
 | 
			
		||||
                  <td class="d-none d-lg-table-cell">{{ block.tx_count | number }}</td>
 | 
			
		||||
                  <td>
 | 
			
		||||
                    <div class="progress position-relative">
 | 
			
		||||
@ -94,27 +94,27 @@
 | 
			
		||||
                </tr>
 | 
			
		||||
              </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
            <div class="text-center"><a href="" [routerLink]="['/blocks' | relativeUrl]">View all »</a></div>
 | 
			
		||||
            <div class="text-center"><a href="" [routerLink]="['/blocks' | relativeUrl]" i18n="dashboard.view-all">View all »</a></div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="col mb-4">
 | 
			
		||||
        <div class="card text-center">
 | 
			
		||||
          <div class="card-body">
 | 
			
		||||
            <h5 class="card-title">Latest transactions</h5>
 | 
			
		||||
            <h5 class="card-title" i18n="dashboard.latest-transactions">Latest transactions</h5>
 | 
			
		||||
            <table class="table table-borderless text-left">
 | 
			
		||||
              <thead>
 | 
			
		||||
                <th style="width: 20%;">TXID</th>
 | 
			
		||||
                <th style="width: 35%;" class="text-right d-none d-lg-table-cell">Amount</th>
 | 
			
		||||
                <th *ngIf="(network$ | async) === ''" style="width: 20%;" class="text-right d-none d-lg-table-cell">USD</th>
 | 
			
		||||
                <th style="width: 25%;" class="text-right">Fee</th>
 | 
			
		||||
                <th style="width: 20%;" i18n="dashboard.latest-transactions.txid">TXID</th>
 | 
			
		||||
                <th style="width: 35%;" class="text-right d-none d-lg-table-cell" i18n="dashboard.latest-transactions.amount">Amount</th>
 | 
			
		||||
                <th *ngIf="(network$ | async) === ''" style="width: 20%;" class="text-right d-none d-lg-table-cell" i18n="dashboard.latest-transactions.USD">USD</th>
 | 
			
		||||
                <th style="width: 25%;" class="text-right" i18n="dashboard.latest-transactions.fee">Fee</th>
 | 
			
		||||
              </thead>
 | 
			
		||||
              <tbody>
 | 
			
		||||
                <tr *ngFor="let transaction of transactions$ | async; let i = index;">
 | 
			
		||||
                  <td><a [routerLink]="['/tx' | relativeUrl, transaction.txid]">{{ transaction.txid | shortenString : 10 }}</a></td>
 | 
			
		||||
                  <td class="text-right d-none d-lg-table-cell"><app-amount [satoshis]="transaction.value" digitsInfo="1.8-8" [noFiat]="true"></app-amount></td>
 | 
			
		||||
                  <td *ngIf="(network$ | async) === ''" class="text-right d-none d-lg-table-cell"><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
 | 
			
		||||
                  <td class="text-right">{{ transaction.fee / (transaction.weight / 4) | number : '1.1-1' }} sat/vB</td>
 | 
			
		||||
                  <td class="text-right">{{ transaction.fee / (transaction.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
              </tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
@ -133,8 +133,14 @@
 | 
			
		||||
    </div>
 | 
			
		||||
  </button>
 | 
			
		||||
 | 
			
		||||
  <div [formGroup]="languageForm" class="text-small text-center mt-4">
 | 
			
		||||
    <select formControlName="language" class="form-control form-control-secondary form-control-sm mx-auto" style="width: 130px;" (change)="changeLanguage()">
 | 
			
		||||
      <option *ngFor="let lang of languages" [value]="lang.code">{{ lang.name }}</option>
 | 
			
		||||
    </select>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="text-small text-center mt-3">
 | 
			
		||||
    <a [routerLink]="['/terms-of-service']">Terms of Service</a>
 | 
			
		||||
    <a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
@ -153,15 +159,15 @@
 | 
			
		||||
  <table style="width: 100%;">
 | 
			
		||||
    <tr>
 | 
			
		||||
      <td>
 | 
			
		||||
        <h5 class="card-title">Mempool size</h5>
 | 
			
		||||
        <h5 class="card-title" i18n="dashboard.mempool-size|Mempool size">Mempool size</h5>
 | 
			
		||||
        <p class="card-text" *ngIf="(mempoolBlocksData$ | async) as mempoolBlocksData; else loading">
 | 
			
		||||
          {{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} block<span [hidden]="mempoolBlocksData.blocks <= 1">s</span>)
 | 
			
		||||
          {{ mempoolBlocksData.size | bytes }} ({{ mempoolBlocksData.blocks }} <span [hidden]="mempoolBlocksData.blocks == 1" i18n="dashboard.block">block</span><span [hidden]="mempoolBlocksData.blocks != 1">blocks</span>)
 | 
			
		||||
        </p>
 | 
			
		||||
      </td>
 | 
			
		||||
      <td>
 | 
			
		||||
        <h5 class="card-title">Unconfirmed</h5>
 | 
			
		||||
        <h5 class="card-title" i18n="dashboard.unconfirmed|Unconfirmed count">Unconfirmed</h5>
 | 
			
		||||
        <p class="card-text" *ngIf="mempoolInfoData.value; else loading">
 | 
			
		||||
          {{ mempoolInfoData.value.memPoolInfo.size | number }} TXs
 | 
			
		||||
          {{ mempoolInfoData.value.memPoolInfo.size | number }} <span i18n="dashboard.txs">TXs</span>
 | 
			
		||||
        </p>
 | 
			
		||||
      </td>
 | 
			
		||||
    </tr>
 | 
			
		||||
@ -169,14 +175,14 @@
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
<ng-template #txPerSecond let-mempoolInfoData>
 | 
			
		||||
  <h5 class="card-title">Incoming transactions</h5>
 | 
			
		||||
  <h5 class="card-title" i18n="dashboard.incoming-transactions">Incoming transactions</h5>
 | 
			
		||||
  <ng-template [ngIf]="mempoolInfoData.value" [ngIfElse]="loading">
 | 
			
		||||
    <span *ngIf="mempoolInfoData.value.vBytesPerSecond === 0; else inSync">
 | 
			
		||||
       <span class="badge badge-pill badge-warning">Backend is synchronizing</span>
 | 
			
		||||
       <span class="badge badge-pill badge-warning" i18n="dashboard.backend-is-synchronizing">Backend is synchronizing</span>
 | 
			
		||||
    </span>
 | 
			
		||||
    <ng-template #inSync>
 | 
			
		||||
      <div class="progress sub-text" style="max-width: 250px;">
 | 
			
		||||
        <div class="progress-bar {{ mempoolInfoData.value.progressClass }}" style="padding: 4px;" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth}">{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} vB/s</div>
 | 
			
		||||
        <div class="progress-bar {{ mempoolInfoData.value.progressClass }}" style="padding: 4px;" role="progressbar" [ngStyle]="{'width': mempoolInfoData.value.progressWidth}">{{ mempoolInfoData.value.vBytesPerSecond | ceil | number }} <ng-template i18n="shared.vbytes-per-second|vB/s">vB/s</ng-template></div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ng-template>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
@ -185,7 +191,7 @@
 | 
			
		||||
<ng-template #difficultyEpoch>
 | 
			
		||||
  <div class="card text-center">
 | 
			
		||||
    <div class="card-body more-padding">
 | 
			
		||||
      <h5 class="card-title">Difficulty adjustment</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="dashboard.difficulty-adjustment">Difficulty adjustment</h5>
 | 
			
		||||
      <div class="progress" *ngIf="(difficultyEpoch$ | async) as epochData; else loading">
 | 
			
		||||
        <div class="progress-bar" role="progressbar" style="width: 15%; background-color: #105fb0" [ngStyle]="{'width': epochData.base}"><ng-template [ngIf]="epochData.change > 0">+</ng-template>{{ epochData.change | number: '1.0-2' }}%</div>
 | 
			
		||||
        <div class="progress-bar bg-success" role="progressbar" style="width: 0%" [ngStyle]="{'width': epochData.green}"></div>
 | 
			
		||||
@ -193,4 +199,4 @@
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</ng-template>
 | 
			
		||||
</ng-template>
 | 
			
		||||
 | 
			
		||||
@ -7,10 +7,12 @@ import { MempoolInfo, TransactionStripped } from '../interfaces/websocket.interf
 | 
			
		||||
import { ApiService } from '../services/api.service';
 | 
			
		||||
import { StateService } from '../services/state.service';
 | 
			
		||||
import * as Chartist from '@mempool/chartist';
 | 
			
		||||
import { formatDate } from '@angular/common';
 | 
			
		||||
import { DOCUMENT, formatDate } from '@angular/common';
 | 
			
		||||
import { WebsocketService } from '../services/websocket.service';
 | 
			
		||||
import { SeoService } from '../services/seo.service';
 | 
			
		||||
import { StorageService } from '../services/storage.service';
 | 
			
		||||
import { FormBuilder, FormGroup } from '@angular/forms';
 | 
			
		||||
import { languages, Language } from '../app.constants';
 | 
			
		||||
 | 
			
		||||
interface MempoolBlocksData {
 | 
			
		||||
  blocks: number;
 | 
			
		||||
@ -55,6 +57,8 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
  mempoolTransactionsWeightPerSecondData: any;
 | 
			
		||||
  mempoolStats$: Observable<MempoolStatsData>;
 | 
			
		||||
  transactionsWeightPerSecondOptions: any;
 | 
			
		||||
  languageForm: FormGroup;
 | 
			
		||||
  languages: Language[];
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    @Inject(LOCALE_ID) private locale: string,
 | 
			
		||||
@ -63,14 +67,22 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
    private websocketService: WebsocketService,
 | 
			
		||||
    private seoService: SeoService,
 | 
			
		||||
    private storageService: StorageService,
 | 
			
		||||
    private formBuilder: FormBuilder,
 | 
			
		||||
    @Inject(DOCUMENT) private document: Document
 | 
			
		||||
  ) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.languages = languages;
 | 
			
		||||
    this.seoService.resetTitle();
 | 
			
		||||
    this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
 | 
			
		||||
    this.network$ = merge(of(''), this.stateService.networkChanged$);
 | 
			
		||||
    this.collapseLevel = this.storageService.getValue('dashboard-collapsed') || 'one';
 | 
			
		||||
 | 
			
		||||
    this.languageForm = this.formBuilder.group({
 | 
			
		||||
      language: ['']
 | 
			
		||||
    });
 | 
			
		||||
    this.setLanguageFromUrl();
 | 
			
		||||
 | 
			
		||||
    this.mempoolInfoData$ = combineLatest([
 | 
			
		||||
      this.stateService.mempoolInfo$,
 | 
			
		||||
      this.stateService.vbytesPerSecond$
 | 
			
		||||
@ -232,4 +244,21 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
    }
 | 
			
		||||
    this.storageService.setValue('dashboard-collapsed', this.collapseLevel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setLanguageFromUrl() {
 | 
			
		||||
    const urlLanguage = this.document.location.pathname.split('/')[1];
 | 
			
		||||
    if (urlLanguage === '') {
 | 
			
		||||
      this.languageForm.get('language').setValue('en');
 | 
			
		||||
    } else if (this.languages.map((lang) => lang.code).indexOf(urlLanguage) > -1) {
 | 
			
		||||
      this.languageForm.get('language').setValue(urlLanguage);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  changeLanguage() {
 | 
			
		||||
    const language = this.languageForm.get('language').value;
 | 
			
		||||
    this.document.location.href = (language === 'en' ? '/' : '/' + language);
 | 
			
		||||
    try {
 | 
			
		||||
      document.cookie = `lang=${language}; expires=Thu, 18 Dec 2050 12:00:00 UTC; path=/`;
 | 
			
		||||
    } catch (e) { }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2226
									
								
								frontend/src/locale/messages.cs.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2226
									
								
								frontend/src/locale/messages.cs.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2226
									
								
								frontend/src/locale/messages.de.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2226
									
								
								frontend/src/locale/messages.de.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2016
									
								
								frontend/src/locale/messages.en_US.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2016
									
								
								frontend/src/locale/messages.en_US.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2226
									
								
								frontend/src/locale/messages.es.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2226
									
								
								frontend/src/locale/messages.es.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2217
									
								
								frontend/src/locale/messages.fa.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2217
									
								
								frontend/src/locale/messages.fa.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2134
									
								
								frontend/src/locale/messages.fr.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2134
									
								
								frontend/src/locale/messages.fr.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2226
									
								
								frontend/src/locale/messages.ja.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2226
									
								
								frontend/src/locale/messages.ja.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2067
									
								
								frontend/src/locale/messages.ko.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2067
									
								
								frontend/src/locale/messages.ko.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2154
									
								
								frontend/src/locale/messages.nl.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2154
									
								
								frontend/src/locale/messages.nl.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2224
									
								
								frontend/src/locale/messages.nn.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2224
									
								
								frontend/src/locale/messages.nn.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2046
									
								
								frontend/src/locale/messages.pl.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2046
									
								
								frontend/src/locale/messages.pl.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2187
									
								
								frontend/src/locale/messages.pt.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2187
									
								
								frontend/src/locale/messages.pt.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2203
									
								
								frontend/src/locale/messages.pt_BR.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2203
									
								
								frontend/src/locale/messages.pt_BR.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2183
									
								
								frontend/src/locale/messages.sl.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2183
									
								
								frontend/src/locale/messages.sl.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2226
									
								
								frontend/src/locale/messages.sv.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2226
									
								
								frontend/src/locale/messages.sv.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2167
									
								
								frontend/src/locale/messages.tr.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2167
									
								
								frontend/src/locale/messages.tr.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2226
									
								
								frontend/src/locale/messages.uk.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2226
									
								
								frontend/src/locale/messages.uk.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2017
									
								
								frontend/src/locale/messages.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2017
									
								
								frontend/src/locale/messages.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2158
									
								
								frontend/src/locale/messages.zh.xlf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2158
									
								
								frontend/src/locale/messages.zh.xlf
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -97,6 +97,15 @@ body {
 | 
			
		||||
  color: #000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-control.form-control-secondary {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: #2d3348;
 | 
			
		||||
  border: 1px solid #2d3348;
 | 
			
		||||
}
 | 
			
		||||
.form-control.form-control-secondary:focus {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.h2-match-table {
 | 
			
		||||
  padding-left: .65rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
var https = require('https');
 | 
			
		||||
var fs = require('fs');
 | 
			
		||||
 | 
			
		||||
var PATH = 'dist/mempool/browser/resources/';
 | 
			
		||||
var PATH = 'dist/mempool/en-US/resources/';
 | 
			
		||||
if (process.argv[2] && process.argv[2] === 'dev') {
 | 
			
		||||
  PATH = 'src/resources/';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										200
									
								
								production/nginx-mempool.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								production/nginx-mempool.conf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,200 @@
 | 
			
		||||
		root /mempool/public_html/mainnet/;
 | 
			
		||||
 | 
			
		||||
		index index.html;
 | 
			
		||||
 | 
			
		||||
		add_header Onion-Location http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion$request_uri;
 | 
			
		||||
		add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
 | 
			
		||||
 | 
			
		||||
		set $frameOptions "DENY";
 | 
			
		||||
		set $contentSecurityPolicy "frame-ancestors 'none'";
 | 
			
		||||
		if ($http_referer ~ ^https://mempool.space/)
 | 
			
		||||
		{
 | 
			
		||||
			set $frameOptions "ALLOW-FROM https://mempool.space";
 | 
			
		||||
			set $contentSecurityPolicy "frame-ancestors https://mempool.space";
 | 
			
		||||
		}
 | 
			
		||||
		if ($http_referer ~ ^https://mempool.ninja/)
 | 
			
		||||
		{
 | 
			
		||||
			set $frameOptions "ALLOW-FROM https://mempool.ninja";
 | 
			
		||||
			set $contentSecurityPolicy "frame-ancestors https://mempool.ninja";
 | 
			
		||||
		}
 | 
			
		||||
		if ($http_referer ~ ^https://node100.bitcoin.wiz.biz/)
 | 
			
		||||
		{
 | 
			
		||||
			set $frameOptions "ALLOW-FROM https://node100.bitcoin.wiz.biz";
 | 
			
		||||
			set $contentSecurityPolicy "frame-ancestors https://node100.bitcoin.wiz.biz";
 | 
			
		||||
		}
 | 
			
		||||
		if ($http_referer ~ ^https://wiz.biz/)
 | 
			
		||||
		{
 | 
			
		||||
			set $frameOptions "ALLOW-FROM https://wiz.biz";
 | 
			
		||||
			set $contentSecurityPolicy "frame-ancestors https://wiz.biz";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		add_header X-Frame-Options $frameOptions;
 | 
			
		||||
		add_header Content-Security-Policy $contentSecurityPolicy;
 | 
			
		||||
 | 
			
		||||
		# fallback for all URLs i.e. /address/foo /tx/foo /block/000
 | 
			
		||||
		location / {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files /$lang/$uri /$lang/$uri/ $uri $uri/ /en-US/$uri @index;
 | 
			
		||||
# /$lang/index.html /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location @index {
 | 
			
		||||
			add_header Cache-Control must-revalidate;
 | 
			
		||||
			try_files /$lang/index.html /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# location block using regex are matched in order
 | 
			
		||||
 | 
			
		||||
		# used to rewrite resources from /<lang>/ to /en-US/
 | 
			
		||||
		location ~ ^/(ar|bg|bs|ca|cs|da|de|et|el|es|eo|eu|fa|fr|gl|ko|hr|id|it|he|ka|lv|lt|hu|mk|ms|nl|ja|no|nb|nn|pl|pt|pt-BR|ro|ru|sk|sl|sr|sh|fi|sv|th|tr|uk|vi|zh)/resources/ {
 | 
			
		||||
			rewrite ^/[a-zA-Z-]*/resources/(.*) /en-US/resources/$1;
 | 
			
		||||
		}
 | 
			
		||||
		# used for cookie override
 | 
			
		||||
		location ~ ^/(ar|bg|bs|ca|cs|da|de|et|el|es|eo|eu|fa|fr|gl|ko|hr|id|it|he|ka|lv|lt|hu|mk|ms|nl|ja|no|nb|nn|pl|pt|pt-BR|ro|ru|sk|sl|sr|sh|fi|sv|th|tr|uk|vi|zh)/ {
 | 
			
		||||
			try_files $uri $uri/ /$1/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# add /sitemap for production SEO
 | 
			
		||||
		location /sitemap {
 | 
			
		||||
			try_files $uri =410;
 | 
			
		||||
		}
 | 
			
		||||
		# old /explorer redirect from v1 days
 | 
			
		||||
		location /explorer {
 | 
			
		||||
			rewrite /explorer/(.*) https://$host/$1 permanent;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# static API docs
 | 
			
		||||
		location = /api {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /api/ {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /liquid/api {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /liquid/api/ {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /testnet/api {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /testnet/api/ {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /bisq/api {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /bisq/api/ {
 | 
			
		||||
			#return 302 https://mempool.space/$request_uri;
 | 
			
		||||
			try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# mainnet API
 | 
			
		||||
		location /api/v1/donations {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999;
 | 
			
		||||
			# don't rate limit this API prefix
 | 
			
		||||
		}
 | 
			
		||||
		location /api/v1/donations/images {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999;
 | 
			
		||||
			proxy_cache cache;
 | 
			
		||||
			proxy_cache_valid 200 1d;
 | 
			
		||||
		}
 | 
			
		||||
		location /api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3000/;
 | 
			
		||||
			limit_req burst=50 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# liquid API
 | 
			
		||||
		location /liquid/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8998/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /liquid/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8998/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /liquid/api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3001/;
 | 
			
		||||
			limit_req burst=50 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# testnet API
 | 
			
		||||
		location /testnet/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8997/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /testnet/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8997/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /testnet/api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3002/;
 | 
			
		||||
			limit_req burst=50 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# bisq API
 | 
			
		||||
		location /bisq/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api/v1/markets {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/api/v1/bisq/markets;
 | 
			
		||||
			#limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/api/v1/bisq;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# mainnet API
 | 
			
		||||
		location /ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /ws/mainnet {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /ws/liquid {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8998/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /ws/testnet {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8997/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
user nobody;
 | 
			
		||||
 | 
			
		||||
pid /var/run/nginx.pid;
 | 
			
		||||
 | 
			
		||||
worker_processes auto;
 | 
			
		||||
@ -38,10 +37,6 @@ http {
 | 
			
		||||
	# number of requests per connection, does not affect SPDY
 | 
			
		||||
	keepalive_requests 100;
 | 
			
		||||
 | 
			
		||||
	types_hash_max_size 2048;
 | 
			
		||||
 | 
			
		||||
	proxy_cache off;
 | 
			
		||||
 | 
			
		||||
	# enable gzip compression
 | 
			
		||||
	gzip on;
 | 
			
		||||
	gzip_vary on;
 | 
			
		||||
@ -55,203 +50,117 @@ http {
 | 
			
		||||
	client_max_body_size 10m;
 | 
			
		||||
 | 
			
		||||
	# proxy cache
 | 
			
		||||
	proxy_cache off;
 | 
			
		||||
	proxy_cache_path /var/cache/nginx keys_zone=cache:20m levels=1:2 inactive=600s max_size=500m;
 | 
			
		||||
	types_hash_max_size 2048;
 | 
			
		||||
 | 
			
		||||
	# rate limit requests
 | 
			
		||||
	limit_req_zone $binary_remote_addr zone=api:5m rate=50r/m;
 | 
			
		||||
	limit_req_zone $binary_remote_addr zone=electrs:5m rate=1000r/m;
 | 
			
		||||
	limit_req_zone $binary_remote_addr zone=api:5m rate=200r/m;
 | 
			
		||||
	limit_req_zone $binary_remote_addr zone=electrs:5m rate=2000r/m;
 | 
			
		||||
	limit_req_status 429;
 | 
			
		||||
 | 
			
		||||
	# rate limit connections
 | 
			
		||||
	limit_conn_zone $binary_remote_addr zone=websocket:10m;
 | 
			
		||||
	limit_conn_status 429;
 | 
			
		||||
 | 
			
		||||
	server {
 | 
			
		||||
		listen 80 backlog=1024;
 | 
			
		||||
		listen [::]:80 backlog=1024;
 | 
			
		||||
	map $http_accept_language $header_lang {
 | 
			
		||||
		default en-US;
 | 
			
		||||
		~*^en-US en-US;
 | 
			
		||||
		~*^en en-US;
 | 
			
		||||
	        ~*^cs cs;
 | 
			
		||||
	        ~*^de de;
 | 
			
		||||
	        ~*^es es;
 | 
			
		||||
	        ~*^fa fa;
 | 
			
		||||
	        ~*^fr fr;
 | 
			
		||||
	        ~*^ja ja;
 | 
			
		||||
	        ~*^nl nl;
 | 
			
		||||
	        ~*^nn nn;
 | 
			
		||||
	        ~*^pt pt;
 | 
			
		||||
	        ~*^sl sl;
 | 
			
		||||
	        ~*^sv sv;
 | 
			
		||||
	        ~*^tr tr;
 | 
			
		||||
	        ~*^uk uk;
 | 
			
		||||
	        ~*^zh zh;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
		server_name mempool.space;
 | 
			
		||||
	map $cookie_lang $lang {
 | 
			
		||||
		default $header_lang;
 | 
			
		||||
		~*^en-US en-US;
 | 
			
		||||
		~*^en en-US;
 | 
			
		||||
	        ~*^cs cs;
 | 
			
		||||
	        ~*^de de;
 | 
			
		||||
	        ~*^es es;
 | 
			
		||||
	        ~*^fa fa;
 | 
			
		||||
	        ~*^fr fr;
 | 
			
		||||
	        ~*^ja ja;
 | 
			
		||||
	        ~*^nl nl;
 | 
			
		||||
	        ~*^nn nn;
 | 
			
		||||
	        ~*^pt pt;
 | 
			
		||||
	        ~*^sl sl;
 | 
			
		||||
	        ~*^sv sv;
 | 
			
		||||
	        ~*^tr tr;
 | 
			
		||||
	        ~*^uk uk;
 | 
			
		||||
	        ~*^zh zh;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server {
 | 
			
		||||
		listen 80;
 | 
			
		||||
		server_name mempool.space mempool.ninja bsq.ninja node100.bitcoin.wiz.biz;
 | 
			
		||||
		return 301 https://$host$request_uri;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server {
 | 
			
		||||
		listen 127.0.0.1:81 backlog=1024;
 | 
			
		||||
		listen [::]:443 ssl default http2 backlog=1024;
 | 
			
		||||
		listen 443 ssl http2;
 | 
			
		||||
		server_name bsq.ninja;
 | 
			
		||||
		ssl_certificate /usr/local/etc/letsencrypt/live/bsq.ninja/fullchain.pem;
 | 
			
		||||
		ssl_certificate_key /usr/local/etc/letsencrypt/live/bsq.ninja/privkey.pem;
 | 
			
		||||
		include /usr/local/etc/letsencrypt/options-ssl-nginx.conf;
 | 
			
		||||
		ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem;
 | 
			
		||||
 | 
			
		||||
		set $redirect_uri https://mempool.space/bisq;
 | 
			
		||||
		if ($uri = /tx.html) {
 | 
			
		||||
			set $redirect_uri https://mempool.space/bisq/tx/$arg_tx;
 | 
			
		||||
		}
 | 
			
		||||
		if ($uri = /txo.html) {
 | 
			
		||||
			set $redirect_uri https://mempool.space/bisq/tx/$arg_txo;
 | 
			
		||||
		}
 | 
			
		||||
		if ($uri = /Address.html) {
 | 
			
		||||
			set $redirect_uri https://mempool.space/bisq/address/$arg_addr;
 | 
			
		||||
		}
 | 
			
		||||
		return 301 $redirect_uri;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server {
 | 
			
		||||
		listen 443 ssl http2;
 | 
			
		||||
		server_name node100.bitcoin.wiz.biz;
 | 
			
		||||
		ssl_certificate /usr/local/etc/letsencrypt/live/node100.bitcoin.wiz.biz/fullchain.pem;
 | 
			
		||||
		ssl_certificate_key /usr/local/etc/letsencrypt/live/node100.bitcoin.wiz.biz/privkey.pem;
 | 
			
		||||
		include /usr/local/etc/letsencrypt/options-ssl-nginx.conf;
 | 
			
		||||
		ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem;
 | 
			
		||||
 | 
			
		||||
		include /usr/local/etc/nginx/nginx-mempool.conf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server {
 | 
			
		||||
		listen 443 ssl http2;
 | 
			
		||||
		server_name mempool.ninja;
 | 
			
		||||
		ssl_certificate /usr/local/etc/letsencrypt/live/mempool.ninja/fullchain.pem;
 | 
			
		||||
		ssl_certificate_key /usr/local/etc/letsencrypt/live/mempool.ninja/privkey.pem;
 | 
			
		||||
		include /usr/local/etc/letsencrypt/options-ssl-nginx.conf;
 | 
			
		||||
		ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem;
 | 
			
		||||
 | 
			
		||||
		include /usr/local/etc/nginx/nginx-mempool.conf;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	server {
 | 
			
		||||
		listen 127.0.0.1:81;
 | 
			
		||||
		listen 443 ssl default http2 backlog=1024;
 | 
			
		||||
 | 
			
		||||
		server_name mempool.space;
 | 
			
		||||
 | 
			
		||||
		ssl_certificate /usr/local/etc/letsencrypt/live/mempool.space/fullchain.pem;
 | 
			
		||||
		ssl_certificate_key /usr/local/etc/letsencrypt/live/mempool.space/privkey.pem;
 | 
			
		||||
		include /usr/local/etc/letsencrypt/options-ssl-nginx.conf;
 | 
			
		||||
		ssl_dhparam /usr/local/etc/letsencrypt/ssl-dhparams.pem;
 | 
			
		||||
 | 
			
		||||
		root /mempool/public_html/mainnet/;
 | 
			
		||||
		index index.html;
 | 
			
		||||
 | 
			
		||||
		# security headers
 | 
			
		||||
 | 
			
		||||
		set $frameOptions "DENY";
 | 
			
		||||
		set $contentSecurityPolicy "frame-ancestors 'none'";
 | 
			
		||||
		if ($http_referer ~ ^https://mempool.space/)
 | 
			
		||||
		{
 | 
			
		||||
			set $frameOptions "ALLOW-FROM https://mempool.space";
 | 
			
		||||
			set $contentSecurityPolicy "frame-ancestors https://mempool.space";
 | 
			
		||||
		}
 | 
			
		||||
		if ($http_referer ~ ^https://wiz.biz/)
 | 
			
		||||
		{
 | 
			
		||||
			set $frameOptions "ALLOW-FROM https://wiz.biz";
 | 
			
		||||
			set $contentSecurityPolicy "frame-ancestors https://wiz.biz";
 | 
			
		||||
		}
 | 
			
		||||
		add_header X-Frame-Options $frameOptions;
 | 
			
		||||
		add_header Content-Security-Policy $contentSecurityPolicy;
 | 
			
		||||
		add_header Link "<https://mempool.space$request_uri>; rel=\"canonical\"";
 | 
			
		||||
		add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
 | 
			
		||||
		#add_header Onion-Location http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion$request_uri;
 | 
			
		||||
 | 
			
		||||
		# /
 | 
			
		||||
 | 
			
		||||
		location / {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#		# /sitemap
 | 
			
		||||
#		location /sitemap {
 | 
			
		||||
#			try_files $uri =410;
 | 
			
		||||
#		}
 | 
			
		||||
#
 | 
			
		||||
#		# /explorer
 | 
			
		||||
#		location /explorer {
 | 
			
		||||
#			rewrite /explorer/(.*) https://$host/$1 permanent;
 | 
			
		||||
#		}
 | 
			
		||||
		
 | 
			
		||||
		# /api
 | 
			
		||||
 | 
			
		||||
		location = /api {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /api/ {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location /api/v1/donations/images {
 | 
			
		||||
			# don't rate limit this URL prefix
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999;
 | 
			
		||||
			proxy_cache cache;
 | 
			
		||||
			proxy_cache_valid 200 1d;
 | 
			
		||||
		}
 | 
			
		||||
		location /api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
			limit_conn websocket 10;
 | 
			
		||||
		}
 | 
			
		||||
		location /api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3000/;
 | 
			
		||||
			limit_req burst=100 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# /mainnet/api
 | 
			
		||||
 | 
			
		||||
		location = /mainnet/api {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /mainnet/api/ {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location /mainnet/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
			limit_conn websocket 10;
 | 
			
		||||
		}
 | 
			
		||||
		location /mainnet/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8999/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /mainnet/api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3000/;
 | 
			
		||||
			limit_req burst=100 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# /liquid/api
 | 
			
		||||
 | 
			
		||||
		location = /liquid/api {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /liquid/api/ {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location /liquid/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8998/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
			limit_conn websocket 10;
 | 
			
		||||
		}
 | 
			
		||||
		location /liquid/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8998/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /liquid/api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3001/;
 | 
			
		||||
			limit_req burst=100 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# /testnet/api
 | 
			
		||||
 | 
			
		||||
		location = /testnet/api {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /testnet/api/ {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location /testnet/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8997/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
			limit_conn websocket 10;
 | 
			
		||||
		}
 | 
			
		||||
		location /testnet/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8997/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /testnet/api/ {
 | 
			
		||||
			proxy_pass http://[::1]:3002/;
 | 
			
		||||
			limit_req burst=100 nodelay zone=electrs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		# /bisq
 | 
			
		||||
 | 
			
		||||
		location = /bisq/api {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location = /bisq/api/ {
 | 
			
		||||
			try_files $uri $uri/ /index.html =404;
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api/v1/ws {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/;
 | 
			
		||||
			proxy_http_version 1.1;
 | 
			
		||||
			proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
			proxy_set_header Connection "Upgrade";
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api/v1/markets {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/api/v1/bisq/markets;
 | 
			
		||||
			#limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api/v1 {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/api/v1;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		location /bisq/api {
 | 
			
		||||
			proxy_pass http://127.0.0.1:8996/api/v1/bisq;
 | 
			
		||||
			limit_req burst=50 nodelay zone=api;
 | 
			
		||||
		}
 | 
			
		||||
		include /usr/local/etc/nginx/nginx-mempool.conf;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								production/test-nginx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								production/test-nginx
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
#!/usr/bin/env zsh
 | 
			
		||||
PROTO=https
 | 
			
		||||
HOSTNAME=mempool.ninja
 | 
			
		||||
URL_BASE=${PROTO}://${HOSTNAME}
 | 
			
		||||
 | 
			
		||||
curltest()
 | 
			
		||||
{
 | 
			
		||||
    read output
 | 
			
		||||
    if [ "${output}" = "$1" ];then
 | 
			
		||||
        echo "PASS: |${output}|"
 | 
			
		||||
    else
 | 
			
		||||
        echo "FAIL: |${output}|"
 | 
			
		||||
        echo "WANT: |$1|"
 | 
			
		||||
        exit 1
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
echo "Starting tests to ${URL_BASE}"
 | 
			
		||||
 | 
			
		||||
echo "Test locale for / with no header or cookie"
 | 
			
		||||
curl -s ${URL_BASE}/ | grep '<html lang' | tr -d '\r\n' | curltest '<html lang="en-US">'
 | 
			
		||||
 | 
			
		||||
echo "Test locale for / with 'ja' lang header and no cookie"
 | 
			
		||||
curl -s -H 'Accept-Language: ja' ${URL_BASE}/ | grep '<html lang' | tr -d '\r\n' | curltest '<html lang="ja">'
 | 
			
		||||
 | 
			
		||||
echo "Test locale for / with 'ja' lang header and 'en' lang cookie"
 | 
			
		||||
curl -s -H 'Accept-Language: ja' --cookie 'lang=en' ${URL_BASE}/ | grep '<html lang' | tr -d '\r\n' | curltest '<html lang="en-US">'
 | 
			
		||||
 | 
			
		||||
echo "Test locale for / with 'ja' lang header and 'sv' lang cookie"
 | 
			
		||||
curl -s -H 'Accept-Language: ja' --cookie 'lang=sv' ${URL_BASE}/ | grep '<html lang' | tr -d '\r\n' | curltest '<html lang="sv">'
 | 
			
		||||
 | 
			
		||||
echo "Test locale for / with 'ja' lang header and 'foo' lang cookie"
 | 
			
		||||
curl -s -H 'Accept-Language: ja' --cookie 'lang=foo' ${URL_BASE}/ | grep '<html lang' | tr -d '\r\n' | curltest '<html lang="ja">'
 | 
			
		||||
 | 
			
		||||
echo "Test rewrite for /resources/pools.json with no header and no cookie"
 | 
			
		||||
curl -s -i ${URL_BASE}/resources/pools.json | grep -i content-type | tr -d '\r\n' | curltest 'content-type: application/json'
 | 
			
		||||
 | 
			
		||||
echo "Test rewrite for /sv/resources/pools.json with no header and no cookie"
 | 
			
		||||
curl -s -i ${URL_BASE}/sv/resources/pools.json | grep -i content-type | tr -d '\r\n' | curltest 'content-type: application/json'
 | 
			
		||||
 | 
			
		||||
echo "Test rewrite for /resources/pools.json with 'ja' lang header and no cookie"
 | 
			
		||||
curl -s -i -H 'Accept-Language: ja' ${URL_BASE}/resources/pools.json | grep -i content-type | tr -d '\r\n' | curltest 'content-type: application/json'
 | 
			
		||||
 | 
			
		||||
echo "Test rewrite for /ja/resources/pools.json with 'ja' lang header and no cookie"
 | 
			
		||||
curl -s -i -H 'Accept-Language: ja' ${URL_BASE}/ja/resources/pools.json | grep -i content-type | tr -d '\r\n' | curltest 'content-type: application/json'
 | 
			
		||||
 | 
			
		||||
#curl -s -i -H 'Accept-Language: sv' ${URL_BASE}/ja/resources/pools.json | grep -i content-type
 | 
			
		||||
#curl -s -i -H 'Accept-Language: foo' --cookie 'lang=sv' ${URL_BASE}/ja/resources/pools.json | grep -i content-type
 | 
			
		||||
#curl -s -i -H 'Accept-Language: foo' --cookie 'lang=sv' ${URL_BASE}/sv/resources/pools.json | grep -i content-type
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user