mirror of
https://github.com/mempool/mempool.git
synced 2025-03-13 11:36:07 +01:00
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
60 changed files with 41992 additions and 451 deletions
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…
Add table
Reference in a new issue