Compare commits

..

1 Commits

Author SHA1 Message Date
wiz
35ad9a2b2b Display legal notices for third party software on About page 2021-12-25 10:48:39 +09:00
129 changed files with 54750 additions and 52740 deletions

View File

@@ -25,7 +25,8 @@ help:
.PHONY: init
init:
@echo ''
mkdir -p $(DATA) $(DATA)/mysql $(DATA)/mysql/data
mkdir -p $(DATA) $(DATA)/mysql $(DATA)/mysql/db-scripts $(DATA)/mysql/data
install -v mariadb-structure.sql $(DATA)/mysql/db-scripts
#REF: https://github.com/mempool/mempool/blob/master/docker/README.md
cat docker/docker-compose.yml > docker-compose.yml
cat backend/mempool-config.sample.json > backend/mempool-config.json

View File

@@ -69,6 +69,11 @@ Create database and grant privileges:
Query OK, 0 rows affected (0.00 sec)
```
From the mempool repo's top-level folder, import the database structure:
```bash
mysql -u mempool -p mempool < mariadb-structure.sql
```
## Mempool Backend
Install mempool dependencies from npm and build the backend:

View File

@@ -1,14 +1,7 @@
import { CpfpInfo, TransactionExtended, TransactionStripped } from '../mempool.interfaces';
import config from '../config';
export class Common {
static nativeAssetId = config.MEMPOOL.NETWORK === 'liquidtestnet' ?
'144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'
: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d';
static _isLiquid = config.MEMPOOL.NETWORK === 'liquid' || config.MEMPOOL.NETWORK === 'liquidtestnet';
static isLiquid(): boolean {
return this._isLiquid;
}
static nativeAssetId = '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d';
static median(numbers: number[]) {
let medianNr = 0;
@@ -114,7 +107,7 @@ export class Common {
totalFees += tx.bestDescendant.fee;
}
tx.effectiveFeePerVsize = Math.max(Common.isLiquid() ? 0.1 : 1, totalFees / (totalWeight / 4));
tx.effectiveFeePerVsize = Math.max(config.MEMPOOL.NETWORK === 'liquid' ? 0.1 : 1, totalFees / (totalWeight / 4));
tx.cpfpChecked = true;
return {

View File

@@ -127,7 +127,7 @@ class DatabaseMigration {
const queries: string[] = [];
if (version < 1) {
if (config.MEMPOOL.NETWORK !== 'liquid' && config.MEMPOOL.NETWORK !== 'liquidtestnet') {
if (config.MEMPOOL.NETWORK !== 'liquid') {
queries.push(`UPDATE statistics SET
vsize_1 = vsize_1 + vsize_2, vsize_2 = vsize_3,
vsize_3 = vsize_4, vsize_4 = vsize_5,

View File

@@ -1,13 +1,12 @@
import config from '../config';
import { MempoolBlock } from '../mempool.interfaces';
import { Common } from './common';
import mempool from './mempool';
import projectedBlocks from './mempool-blocks';
class FeeApi {
constructor() { }
defaultFee = Common.isLiquid() ? 0.1 : 1;
defaultFee = config.MEMPOOL.NETWORK === 'liquid' ? 0.1 : 1;
public getRecommendedFee() {
const pBlocks = projectedBlocks.getMempoolBlocks();

View File

@@ -4,7 +4,6 @@ import logger from '../logger';
import { Statistic, TransactionExtended, OptimizedStatistic } from '../mempool.interfaces';
import config from '../config';
import { Common } from './common';
class Statistics {
protected intervalTimer: NodeJS.Timer | undefined;
@@ -91,9 +90,9 @@ class Statistics {
memPoolArray.forEach((transaction) => {
for (let i = 0; i < logFees.length; i++) {
if (
(Common.isLiquid() && (i === lastItem || transaction.effectiveFeePerVsize * 10 < logFees[i + 1]))
(config.MEMPOOL.NETWORK === 'liquid' && (i === lastItem || transaction.effectiveFeePerVsize * 10 < logFees[i + 1]))
||
(!Common.isLiquid() && (i === lastItem || transaction.effectiveFeePerVsize < logFees[i + 1]))
(config.MEMPOOL.NETWORK !== 'liquid' && (i === lastItem || transaction.effectiveFeePerVsize < logFees[i + 1]))
) {
if (weightVsizeFees[logFees[i]]) {
weightVsizeFees[logFees[i]] += transaction.vsize;
@@ -408,7 +407,7 @@ class Statistics {
public async $list1W(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDaysAvg(300, '1 WEEK'); // 5m interval
const query = this.getQueryForDaysAvg(600, '1 WEEK'); // 10m interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);
@@ -421,7 +420,7 @@ class Statistics {
public async $list1M(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDaysAvg(1800, '1 MONTH'); // 30m interval
const query = this.getQueryForDaysAvg(3600, '1 MONTH'); // 1h interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);
@@ -434,7 +433,7 @@ class Statistics {
public async $list3M(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDaysAvg(7200, '3 MONTH'); // 2h interval
const query = this.getQueryForDaysAvg(14400, '3 MONTH'); // 4h interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);
@@ -447,7 +446,7 @@ class Statistics {
public async $list6M(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDaysAvg(10800, '6 MONTH'); // 3h interval
const query = this.getQueryForDaysAvg(21600, '6 MONTH'); // 6h interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);
@@ -460,7 +459,7 @@ class Statistics {
public async $list1Y(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDays(28800, '1 YEAR'); // 8h interval
const query = this.getQueryForDays(43200, '1 YEAR'); // 12h interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);
@@ -473,7 +472,7 @@ class Statistics {
public async $list2Y(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDays(28800, "2 YEAR"); // 8h interval
const query = this.getQueryForDays(86400, "2 YEAR"); // 1d interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);
@@ -486,7 +485,7 @@ class Statistics {
public async $list3Y(): Promise<OptimizedStatistic[]> {
try {
const connection = await DB.pool.getConnection();
const query = this.getQueryForDays(43200, "3 YEAR"); // 12h interval
const query = this.getQueryForDays(86400, "3 YEAR"); // 1d interval
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
connection.release();
return this.mapStatisticToOptimizedStatistic(rows);

View File

@@ -2,7 +2,6 @@ import bitcoinApi from './bitcoin/bitcoin-api-factory';
import { TransactionExtended, TransactionMinerInfo } from '../mempool.interfaces';
import { IEsploraApi } from './bitcoin/esplora-api.interface';
import config from '../config';
import { Common } from './common';
class TransactionUtils {
constructor() { }
@@ -32,8 +31,7 @@ class TransactionUtils {
// @ts-ignore
return transaction;
}
const feePerVbytes = Math.max(Common.isLiquid() ? 0.1 : 1,
(transaction.fee || 0) / (transaction.weight / 4));
const feePerVbytes = Math.max(config.MEMPOOL.NETWORK === 'liquid' ? 0.1 : 1, (transaction.fee || 0) / (transaction.weight / 4));
const transactionExtended: TransactionExtended = Object.assign({
vsize: Math.round(transaction.weight / 4),
feePerVsize: feePerVbytes,

View File

@@ -2,7 +2,7 @@ const configFile = require('../mempool-config.json');
interface IConfig {
MEMPOOL: {
NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid' | 'liquidtestnet';
NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid';
BACKEND: 'esplora' | 'electrum' | 'none';
HTTP_PORT: number;
SPAWN_CLUSTER_PROCS: number;

View File

@@ -24,7 +24,6 @@ import elementsParser from './api/liquid/elements-parser';
import databaseMigration from './api/database-migration';
import syncAssets from './sync-assets';
import icons from './api/liquid/icons';
import { Common } from './api/common';
class Server {
private wss: WebSocket.Server | undefined;
@@ -97,7 +96,7 @@ class Server {
statistics.startStatistics();
}
if (Common.isLiquid()) {
if (config.MEMPOOL.NETWORK === 'liquid') {
icons.loadIcons();
}
@@ -157,7 +156,7 @@ class Server {
if (this.wss) {
websocketHandler.setWebsocketServer(this.wss);
}
if (Common.isLiquid() && config.DATABASE.ENABLED) {
if (config.MEMPOOL.NETWORK === 'liquid' && config.DATABASE.ENABLED) {
blocks.setNewBlockCallback(async () => {
try {
await elementsParser.$parse();
@@ -284,14 +283,14 @@ class Server {
;
}
if (Common.isLiquid()) {
if (config.MEMPOOL.NETWORK === 'liquid') {
this.app
.get(config.MEMPOOL.API_URL_PREFIX + 'assets/icons', routes.getAllLiquidIcon)
.get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', routes.getLiquidIcon)
;
}
if (Common.isLiquid() && config.DATABASE.ENABLED) {
if (config.MEMPOOL.NETWORK === 'liquid' && config.DATABASE.ENABLED) {
this.app
.get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', routes.$getElementsPegsByMonth)
;

View File

@@ -5,9 +5,11 @@
In an empty dir create 2 sub-dirs
```bash
mkdir -p data mysql/data
mkdir -p data mysql/data mysql/db-scripts
```
In the `mysql/db-scripts` sub-dir add the `mariadb-structure.sql` file from the mempool repo
Your dir should now look like that:
```bash
@@ -21,6 +23,9 @@ data mysql
data db-scripts
./mysql/data:
./mysql/db-scripts:
mariadb-structure.sql
```
In the main dir add the following `docker-compose.yml`

2
frontend/.gitignore vendored
View File

@@ -50,8 +50,6 @@ Thumbs.db
src/resources/assets.json
src/resources/assets.minimal.json
src/resources/assets-testnet.json
src/resources/assets-testnet.minimal.json
src/resources/pools.json
# environment config

View File

@@ -2,7 +2,6 @@
"TESTNET_ENABLED": false,
"SIGNET_ENABLED": false,
"LIQUID_ENABLED": false,
"LIQUID_TESTNET_ENABLED": false,
"BISQ_ENABLED": false,
"BISQ_SEPARATE_BACKEND": false,
"ITEMS_PER_PAGE": 10,

View File

@@ -24,7 +24,6 @@ PROXY_CONFIG = [
'/api/**', '!/api/v1/ws',
'!/bisq', '!/bisq/**', '!/bisq/',
'!/liquid', '!/liquid/**', '!/liquid/',
'!/liquidtestnet', '!/liquidtestnet/**', '!/liquidtestnet/',
'/testnet/api/**', '/signet/api/**'
],
target: "https://mempool.space",
@@ -58,16 +57,6 @@ PROXY_CONFIG = [
ws: true,
secure: false,
changeOrigin: true
},
{
context: ['/api/liquidtestnet**', '/liquidtestnet/api/**'],
target: "https://liquid.network/testnet",
pathRewrite: {
"^/api/liquidtestnet/": "/liquidtestnet/api"
},
ws: true,
secure: false,
changeOrigin: true
}
];

View File

@@ -105,91 +105,6 @@ let routes: Routes = [
},
],
},
{
path: 'liquidtestnet',
children: [
{
path: '',
component: MasterPageComponent,
children: [
{
path: 'tx/push',
component: PushTransactionComponent,
},
{
path: '',
component: StartComponent,
children: [
{
path: '',
component: DashboardComponent
},
{
path: 'tx/:id',
component: TransactionComponent
},
{
path: 'block/:id',
component: BlockComponent
},
{
path: 'mempool-block/:id',
component: MempoolBlockComponent
},
],
},
{
path: 'blocks',
component: LatestBlocksComponent,
},
{
path: 'graphs',
component: StatisticsComponent,
},
{
path: 'address/:id',
component: AddressComponent
},
{
path: 'asset/:id',
component: AssetComponent
},
{
path: 'assets',
component: AssetsComponent,
},
{
path: 'docs/api/:type',
component: DocsComponent
},
{
path: 'docs/api',
redirectTo: 'docs/api/rest'
},
{
path: 'docs',
redirectTo: 'docs/api/rest'
},
{
path: 'api',
redirectTo: 'docs/api/rest'
},
],
},
{
path: 'tv',
component: TelevisionComponent
},
{
path: 'status',
component: StatusViewComponent
},
{
path: '**',
redirectTo: ''
},
]
},
{
path: 'liquid',
children: [
@@ -551,94 +466,6 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
},
],
},
{
path: 'testnet',
component: LiquidMasterPageComponent,
children: [
{
path: '',
component: StartComponent,
children: [
{
path: '',
component: DashboardComponent
},
{
path: 'tx/push',
component: PushTransactionComponent,
},
{
path: 'tx/:id',
component: TransactionComponent
},
{
path: 'block/:id',
component: BlockComponent
},
{
path: 'mempool-block/:id',
component: MempoolBlockComponent
},
],
},
{
path: 'blocks',
component: LatestBlocksComponent,
},
{
path: 'graphs',
component: StatisticsComponent,
},
{
path: 'address/:id',
component: AddressComponent
},
{
path: 'asset/:id',
component: AssetComponent
},
{
path: 'assets',
component: AssetsComponent,
},
{
path: 'docs/api/:type',
component: DocsComponent
},
{
path: 'docs/api',
redirectTo: 'docs/api/rest'
},
{
path: 'docs',
redirectTo: 'docs/api/rest'
},
{
path: 'api',
redirectTo: 'docs/api/rest'
},
{
path: 'about',
component: AboutComponent,
},
{
path: 'terms-of-service',
component: TermsOfServiceComponent
},
{
path: 'privacy-policy',
component: PrivacyPolicyComponent
},
{
path: 'trademark-policy',
component: TrademarkPolicyComponent
},
{
path: 'sponsor',
component: SponsorComponent,
},
],
},
{
path: 'tv',
component: TelevisionComponent

View File

@@ -7,7 +7,6 @@ import { ActivatedRoute, Router } from '@angular/router';
import { merge, combineLatest, Observable } from 'rxjs';
import { AssetExtended } from '../interfaces/electrs.interface';
import { SeoService } from '../services/seo.service';
import { StateService } from '../services/state.service';
@Component({
selector: 'app-assets',
@@ -16,8 +15,7 @@ import { StateService } from '../services/state.service';
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AssetsComponent implements OnInit {
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
nativeAssetId = environment.nativeAssetId;
assets: AssetExtended[];
assetsCache: AssetExtended[];
searchForm: FormGroup;
@@ -36,7 +34,6 @@ export class AssetsComponent implements OnInit {
private route: ActivatedRoute,
private router: Router,
private seoService: SeoService,
private stateService: StateService,
) { }
ngOnInit() {
@@ -55,22 +52,12 @@ export class AssetsComponent implements OnInit {
take(1),
mergeMap(([assets, qp]) => {
this.assets = Object.values(assets);
if (this.stateService.network === 'liquid') {
// @ts-ignore
this.assets.push({
name: 'Liquid Bitcoin',
ticker: 'L-BTC',
asset_id: this.nativeAssetId,
});
} else if (this.stateService.network === 'liquidtestnet') {
// @ts-ignore
this.assets.push({
name: 'Test Liquid Bitcoin',
ticker: 'tL-BTC',
asset_id: this.nativeAssetId,
});
}
// @ts-ignore
this.assets.push({
name: 'Liquid Bitcoin',
ticker: 'L-BTC',
asset_id: this.nativeAssetId,
});
this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name));
this.assetsCache = this.assets;
this.searchForm.get('searchText').enable();

View File

@@ -33,7 +33,7 @@ export class BisqMainDashboardComponent implements OnInit {
) { }
ngOnInit(): void {
this.seoService.resetTitle();
this.seoService.setTitle(`Markets`);
this.websocketService.want(['blocks']);
this.usdPrice$ = this.stateService.conversions$.asObservable().pipe(

View File

@@ -102,10 +102,6 @@
<img class="image" src="/resources/profile/ronindojo.png" />
<span>RoninDojo</span>
</a>
<a href="https://github.com/runcitadel/dashboard" target="_blank" title="Citadel">
<img class="image" src="/resources/profile/runcitadel.svg" />
<span>Citadel</span>
</a>
<a href="https://github.com/spesmilo/electrum" target="_blank" title="Electrum Wallet">
<img class="image" src="/resources/profile/electrum.jpg" />
<span>Electrum</span>
@@ -146,6 +142,10 @@
<img class="image" src="/resources/profile/satpile.jpg" />
<span>Satpile</span>
</a>
<a href="https://github.com/btcontract/lnwallet" target="_blank" title="Bitcoin Lightning Wallet">
<img class="image" src="/resources/profile/blw.png" />
<span>BLW</span>
</a>
</div>
</div>
@@ -204,10 +204,10 @@
</div>
</div>
<div class="copyright">
<div class="legal">
<div class="title">
Copyright &copy; 2019-2021<br>
The Mempool Open Source Project
The Mempool Open Source Project<br>
Copyright &copy; 2019-2021
</div>
<p>
<a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> is free software; you can redistribute it and/or modify it under the terms of (at your option) either:<br>
@@ -223,22 +223,30 @@
<p>
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the full license terms for more details.<br>
</p>
<div class="title">
Trademark Notice<br>
</div>
<div class="title">Trademark Notice</div>
<p>
The Mempool Open Source Project&trade;, mempool.space&trade;, the mempool logo&trade;, the mempool.space logos&trade;, the mempool square logo&trade;, and the mempool blocks logo&trade; are either registered trademarks or trademarks of Mempool Space K.K in Japan, the United States, and/or other countries.
</p>
<p>
While our software is available under an open source software license, the copyright license does not include an implied right or license to use our trademarks. See our <a href="https://mempool.space/trademark-policy">Trademark Policy and Guidelines</a> for more details, published on &lt;https://mempool.space/trademark-policy&gt;.
</p>
<div class="title">Third Party Software</div>
<p>This software incorporates materials from third parties, with permission of the respective licensors and/or copyright holders on the terms provided by such parties as identified below.</p>
<textarea class="thirdPartyLicenses">{{ thirdPartyLicenses$ | async }}</textarea>
</div>
<br><br>
<div class="footer-links">
<a href="/3rdpartylicenses.txt">Third-party Licenses</a>
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a> | <a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
</div>
<br>
<div class="footer-version" *ngIf="officialMempoolSpace">
{{ (backendInfo$ | async)?.hostname }} (v{{ (backendInfo$ | async )?.version }}) [{{ (backendInfo$ | async )?.gitCommit | slice:0:8 }}]
</div>

View File

@@ -116,7 +116,7 @@
&:hover {
text-decoration: none;
img {
transform: scale(1.1);
box-shadow: 0px 0px 20px #1bd8f4;
}
}
img, span{
@@ -137,7 +137,7 @@
}
}
.copyright {
.legal {
text-align: left;
max-width: 620px;
padding: 0px 15px;
@@ -161,16 +161,23 @@
}
}
.thirdPartyLicenses {
display: block;
margin-left: auto;
margin-right: auto;
width: 600px;
height: 30em;
font-family: SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;
font-size: 10px;
border-color: #e83e8c;
background: transparent;
color: #e83e8c;
}
.thirdPartyLicenses > .scroll-pane{
-fx-vbar-policy: always;
}
.footer-links {
display: flex;
flex-direction: column;
a {
display: inline-block;
margin: 15px auto 0px;
&:last-child {
margin: 20px auto 30px;
}
}
}
.footer-version {

View File

@@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, OnInit } from '@
import { WebsocketService } from '../../services/websocket.service';
import { SeoService } from 'src/app/services/seo.service';
import { StateService } from 'src/app/services/state.service';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ApiService } from 'src/app/services/api.service';
import { IBackendInfo } from 'src/app/interfaces/websocket.interface';
@@ -17,6 +18,7 @@ import { map } from 'rxjs/operators';
export class AboutComponent implements OnInit {
backendInfo$: Observable<IBackendInfo>;
sponsors$: Observable<any>;
thirdPartyLicenses$: Observable<string>;
allContributors$: Observable<any>;
frontendGitCommitHash = this.stateService.env.GIT_COMMIT_HASH;
packetJsonVersion = this.stateService.env.PACKAGE_JSON_VERSION;
@@ -27,6 +29,7 @@ export class AboutComponent implements OnInit {
private websocketService: WebsocketService,
private seoService: SeoService,
public stateService: StateService,
private httpClient: HttpClient,
private apiService: ApiService,
private router: Router,
@Inject(LOCALE_ID) public locale: string,
@@ -38,6 +41,7 @@ export class AboutComponent implements OnInit {
this.websocketService.want(['blocks']);
this.sponsors$ = this.apiService.getDonation$();
this.thirdPartyLicenses$ = this.getThirdPartyLicenses$();
this.allContributors$ = this.apiService.getContributor$().pipe(
map((contributors) => {
return {
@@ -48,6 +52,10 @@ export class AboutComponent implements OnInit {
);
}
getThirdPartyLicenses$(): Observable<string> {
return this.httpClient.get<string>('/3rdpartylicenses.txt', { responseType: 'text' as 'json' });
}
sponsor() {
if (this.officialMempoolSpace && this.stateService.env.BASE_MODULE === 'mempool') {
this.router.navigateByUrl('/sponsor');

View File

@@ -99,7 +99,7 @@ export class AddressComponent implements OnInit, OnDestroy {
.pipe(
filter((address) => !!address),
tap((address: Address) => {
if ((this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') && /^([m-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) {
if (this.stateService.network === 'liquid' && /^([m-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) {
this.apiService.validateAddress$(address.address)
.subscribe((addressInfo) => {
this.addressInfo = addressInfo;

View File

@@ -2,13 +2,12 @@
<span class="fiat">{{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
</ng-container>
<ng-template #viewFiatVin>
<ng-template [ngIf]="(network === 'liquid' || network === 'liquidtestnet') && (satoshis === undefined || satoshis === null)" [ngIfElse]="default">
<ng-template [ngIf]="network === 'liquid' && (satoshis === undefined || satoshis === null)" [ngIfElse]="default">
<span i18n="shared.confidential">Confidential</span>
</ng-template>
<ng-template #default>
&lrm;{{ satoshis / 100000000 | number : digitsInfo }}
<span class="symbol"><ng-template [ngIf]="network === 'liquid'">L-</ng-template>
<ng-template [ngIf]="network === 'liquidtestnet'">tL-</ng-template>
<ng-template [ngIf]="network === 'testnet'">t</ng-template>
<ng-template [ngIf]="network === 'signet'">s</ng-template>BTC</span>
</ng-template>

View File

@@ -31,7 +31,7 @@
<td i18n="asset.issuer|Liquid Asset issuer">Issuer</td>
<td><a target="_blank" href="{{ 'http://' + assetContract[0] }}">{{ assetContract[0] }}</a></td>
</tr>
<tr *ngIf="asset.issuance_txin">
<tr *ngIf="!isNativeAsset">
<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>
@@ -42,15 +42,15 @@
<div class="col">
<table class="table table-borderless table-striped">
<tbody>
<tr *ngIf="isNativeAsset && asset.chain_stats.peg_in_amount">
<tr *ngIf="isNativeAsset">
<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 && asset.chain_stats.peg_out_amount">
<tr *ngIf="isNativeAsset">
<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="asset.chain_stats.issued_amount">
<tr *ngIf="!isNativeAsset">
<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>
@@ -58,11 +58,11 @@
<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="asset.chain_stats.issued_amount">
<tr *ngIf="!isNativeAsset">
<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 && asset.chain_stats.peg_in_amount">
<tr *ngIf="isNativeAsset">
<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>
@@ -78,7 +78,7 @@
<div class="title-tx">
<h2>
<ng-template [ngIf]="transactions?.length" i18n="asset.M_of_N">{{ (transactions?.length | number) || '?' }} of {{ txCount | number }}&nbsp;</ng-template>
<ng-template [ngIf]="isNativeAsset && network === 'liquid'" [ngIfElse]="defaultAsset" i18n="Liquid native asset transactions title">Peg In/Out and Burn Transactions</ng-template>
<ng-template [ngIf]="isNativeAsset" [ngIfElse]="defaultAsset" i18n="Liquid native asset transactions title">Peg In/Out and Burn Transactions</ng-template>
<ng-template #defaultAsset i18n="Default asset transactions title">Issuance and Burn Transactions</ng-template>
</h2>
</div>

View File

@@ -20,7 +20,7 @@ import { moveDec } from 'src/app/bitcoin.utils';
})
export class AssetComponent implements OnInit, OnDestroy {
network = '';
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
nativeAssetId = environment.nativeAssetId;
asset: Asset;
blindedIssuance: boolean;

View File

@@ -10,7 +10,7 @@
</ng-container>
</a>
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED">
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
<img src="./resources/bisq-logo.png" style="width: 25px; height: 25px;" class="mr-1">
</button>
@@ -21,7 +21,6 @@
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
<button ngbDropdownItem class="mainnet active" routerLink="/"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
<a href="https://liquid.network" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
<a href="https://liquid.network/testnet" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</a>
</div>
</div>

View File

@@ -102,10 +102,6 @@ nav {
background-color: #116761;
}
.liquidtestnet.active {
background-color: #494a4a;
}
.testnet.active {
background-color: #1d486f;
}

View File

@@ -81,12 +81,12 @@
<ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
<tr>
<td i18n="block.total-fees|Total fees in a block">Total fees</td>
<td *ngIf="network !== 'liquid' && network !== 'liquidtestnet'; else liquidTotalFees"><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="fees * 100000000" digitsInfo="1.0-0"></app-fiat></span></td>
<td *ngIf="network !== 'liquid'; else liquidTotalFees"><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="fees * 100000000" digitsInfo="1.0-0"></app-fiat></span></td>
<ng-template #liquidTotalFees>
<td><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount>&nbsp; <app-fiat [value]="fees * 100000000" digitsInfo="1.2-2"></app-fiat></td>
<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' && network !== 'liquidtestnet'">
<tr *ngIf="network !== 'liquid'">
<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> <span class="fiat"><app-fiat [value]="(blockSubsidy + fees) * 100000000" digitsInfo="1.0-0"></app-fiat></span>
@@ -98,7 +98,7 @@
<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' && network !== 'liquidtestnet'">
<tr *ngIf="network !== 'liquid'">
<td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
<td><span class="skeleton-loader"></span></td>
</tr>
@@ -125,7 +125,7 @@
<td class="td-width" i18n="transaction.version">Version</td>
<td>{{ block.version | decimal2hex }} <span *ngIf="displayTaprootStatus() && hasTaproot(block.version)" class="badge badge-success ml-1" >Taproot</span></td>
</tr>
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
<tr *ngIf="network !== 'liquid'">
<td i18n="block.bits">Bits</td>
<td>{{ block.bits | decimal2hex }}</td>
</tr>
@@ -136,7 +136,7 @@
</tbody>
</table>
</div>
<div class="col-sm" *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
<div class="col-sm" *ngIf="network !== 'liquid'">
<table class="table table-borderless table-striped">
<tbody>
<tr>

View File

@@ -8,12 +8,10 @@ import { Observable, of, Subscription } from 'rxjs';
import { StateService } from '../../services/state.service';
import { SeoService } from 'src/app/services/seo.service';
import { WebsocketService } from 'src/app/services/websocket.service';
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
@Component({
selector: 'app-block',
templateUrl: './block.component.html',
providers: [RelativeUrlPipe],
styleUrls: ['./block.component.scss']
})
export class BlockComponent implements OnInit, OnDestroy {
@@ -53,7 +51,6 @@ export class BlockComponent implements OnInit, OnDestroy {
private stateService: StateService,
private seoService: SeoService,
private websocketService: WebsocketService,
private relativeUrlPipe: RelativeUrlPipe,
) { }
ngOnInit() {
@@ -197,7 +194,7 @@ export class BlockComponent implements OnInit, OnDestroy {
if (this.showNextBlocklink) {
this.navigateToNextBlock();
} else {
this.router.navigate([this.relativeUrlPipe.transform('/mempool-block'), '0']);
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/mempool-block/', '0']);
}
}
});
@@ -213,7 +210,7 @@ export class BlockComponent implements OnInit, OnDestroy {
}
setBlockSubsidy() {
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
this.blockSubsidy = 0;
return;
}
@@ -280,13 +277,13 @@ export class BlockComponent implements OnInit, OnDestroy {
return;
}
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight - 2);
this.router.navigate([this.relativeUrlPipe.transform('/block/'),
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/',
block ? block.id : this.block.previousblockhash], { state: { data: { block, blockHeight: this.nextBlockHeight - 2 } } });
}
navigateToNextBlock() {
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight);
this.router.navigate([this.relativeUrlPipe.transform('/block/'),
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/',
block ? block.id : this.nextBlockHeight], { state: { data: { block, blockHeight: this.nextBlockHeight } } });
}

View File

@@ -36,7 +36,6 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
'': ['#9339f4', '#105fb0'],
bisq: ['#9339f4', '#105fb0'],
liquid: ['#116761', '#183550'],
'liquidtestnet': ['#494a4a', '#272e46'],
testnet: ['#1d486f', '#183550'],
signet: ['#6f1d5d', '#471850'],
};
@@ -48,7 +47,7 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
) { }
ngOnInit() {
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
if (this.stateService.network === 'liquid') {
this.feeRounding = '1.0-1';
}
this.emptyBlocks.forEach((b) => this.emptyBlockStyles.push(this.getStyleForEmptyBlock(b)));

View File

@@ -31,7 +31,7 @@
top: 75px;
}
.position-container.liquid, .position-container.liquidtestnet {
.position-container.liquid {
left: 420px;
}
@@ -39,7 +39,7 @@
.position-container {
left: 95%;
}
.position-container.liquid, .position-container.liquidtestnet {
.position-container.liquid {
left: 50%;
}
.position-container.loading {

View File

@@ -27,7 +27,7 @@
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-address-transactions-mempool" (click)="collapseItem.toggle()">GET Address Transactions Mempool</a>
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-address-utxo" (click)="collapseItem.toggle()">GET Address UTXO</a>
<ng-template [ngIf]="network.val === 'liquid' || network.val === 'liquidtestnet'">
<ng-template [ngIf]="network.val === 'liquid'">
<p>Assets</p>
<a [routerLink]="['./']" fragment="get-assets" (click)="collapseItem.toggle()">GET Assets</a>
<a [routerLink]="['./']" fragment="get-assets-icons" (click)="collapseItem.toggle()">GET Assets Icons</a>
@@ -66,7 +66,7 @@
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-cpfp" (click)="collapseItem.toggle()">GET Children Pay for Parent</a>
<a [routerLink]="['./']" fragment="get-transaction" (click)="collapseItem.toggle()">GET Transaction</a>
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-hex" (click)="collapseItem.toggle()">GET Transaction Hex</a>
<a *ngIf="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'" [routerLink]="['./']" fragment="get-transaction-merkleblock-proof" (click)="collapseItem.toggle()">GET Transaction Merkleblock Proof</a>
<a *ngIf="network.val !== 'bisq' && network.val !== 'liquid'" [routerLink]="['./']" fragment="get-transaction-merkleblock-proof" (click)="collapseItem.toggle()">GET Transaction Merkleblock Proof</a>
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-merkle-proof" (click)="collapseItem.toggle()">GET Transaction Merkle Proof</a>
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-outspend" (click)="collapseItem.toggle()">GET Transaction Outspend</a>
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-outspends" (click)="collapseItem.toggle()">GET Transaction Outspends</a>

View File

@@ -24,7 +24,7 @@
<div id="mobile-top-doc-nav" #mobileFixedApiNav class="hide-on-desktop"><app-api-docs-nav [network]="{ val: network$ | async }"></app-api-docs-nav></div>
<div class="api-category" *ngIf="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'">
<div class="api-category" *ngIf="network.val !== 'bisq' && network.val !== 'liquid'">
<div class="endpoint-container" id="get-difficulty-adjustment">
<a class="section-header" [routerLink]="['./']" fragment="get-difficulty-adjustment">GET Difficulty Adjustment <span>General</span></a>
@@ -228,14 +228,14 @@
</div>
<div class="description">
<div class="subtitle" i18n>Description</div>
<div 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' || network.val === 'liquidtestnet'">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></div>
<div 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></div>
</div>
<app-code-template [hostname]="hostname" [code]="code.addressUTXO" [network]="network.val" ></app-code-template>
</div>
</div>
<div class="api-category" *ngIf="network.val === 'liquid' || network.val === 'liquidtestnet'">
<div class="api-category" *ngIf="network.val === 'liquid'">
<div class="endpoint-container" id="get-assets">
<a class="section-header" [routerLink]="['./']" fragment="get-assets">GET Assets <span>Assets</span></a>
@@ -313,7 +313,7 @@
</div>
<div class="description">
<div class="subtitle" i18n>Description</div>
<div 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' || network.val === 'liquidtestnet'"> <code>proof</code>,</ng-container> and <code>previousblockhash</code>.</div>
<div 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>.</div>
</div>
<app-code-template [hostname]="hostname" [code]="code.block" [network]="network.val" ></app-code-template>
</div>
@@ -577,7 +577,7 @@
<app-code-template [hostname]="hostname" [code]="code.transactionHex" [network]="network.val" ></app-code-template>
</div>
<div class="endpoint-container" *ngIf="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'" id="get-transaction-merkleblock-proof">
<div class="endpoint-container" *ngIf="network.val !== 'bisq' && network.val !== 'liquid'" id="get-transaction-merkleblock-proof">
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-merkleblock-proof">GET Transaction Merkleblock Proof <span>Transactions</span></a>
<div class="endpoint">
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>

View File

@@ -3663,7 +3663,7 @@ export class ApiDocsComponent implements OnInit {
};
this.network$.subscribe((network) => {
this.active = (network === 'liquid' || network === 'liquidtestnet') ? 2 : 0;
this.active = (network === 'liquid') ? 2 : 0;
});
}
@@ -3679,7 +3679,7 @@ export class ApiDocsComponent implements OnInit {
if (network === 'signet') {
curlResponse = code.codeSampleSignet.curl;
}
if (network === 'liquid' || network === 'liquidtestnet') {
if (network === 'liquid') {
curlResponse = code.codeSampleLiquid.curl;
}
if (network === 'bisq') {

View File

@@ -26,7 +26,7 @@ export class CodeTemplateComponent implements OnInit {
if (this.network === 'bisq') {
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-bisq-js`;
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-liquid-js`;
}
return npmLink;
@@ -37,7 +37,7 @@ export class CodeTemplateComponent implements OnInit {
if (this.network === 'bisq') {
npmLink = `https://www.npmjs.org/package/@mempool/bisq.js`;
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
npmLink = `https://www.npmjs.org/package/@mempool/liquid.js`;
}
return npmLink;
@@ -50,7 +50,7 @@ export class CodeTemplateComponent implements OnInit {
} else {
codeText = codeText.replace('%{0}', 'bitcoin');
}
if(['', 'main', 'liquid', 'bisq', 'liquidtestnet'].includes(this.network)) {
if(['', 'main', 'liquid', 'bisq'].includes(this.network)) {
codeText = codeText.replace('mempoolJS();', `mempoolJS({
hostname: '${document.location.hostname}'
});`);
@@ -119,7 +119,7 @@ export class CodeTemplateComponent implements OnInit {
if (this.network === 'signet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
}
if (this.network === 'bisq') {
@@ -157,7 +157,7 @@ init();`;
if (this.network === 'signet') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
}
if (this.network === 'bisq') {
@@ -237,7 +237,7 @@ yarn add @mempool/liquid.js`;
if (this.network === 'signet') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleSignet);
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleLiquid);
}
if (this.network === 'bisq') {
@@ -259,7 +259,7 @@ yarn add @mempool/liquid.js`;
if (this.network === 'signet') {
return code.codeSampleSignet.response;
}
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
return code.codeSampleLiquid.response;
}
if (this.network === 'bisq') {

View File

@@ -26,7 +26,7 @@ export class FeesBoxComponent implements OnInit {
) { }
ngOnInit(): void {
this.defaultFee = this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ? 0.1 : 1;
this.defaultFee = this.stateService.network === 'liquid' ? 0.1 : 1;
this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
this.feeEstimations$ = this.stateService.mempoolBlocks$

View File

@@ -1,4 +1,3 @@
<ng-container *ngIf="{ val: network$ | async } as network">
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<a class="navbar-brand" [routerLink]="['/' | relativeUrl]" style="position: relative;">
@@ -11,9 +10,9 @@
</ng-container>
</a>
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED">
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
<img src="./resources/{{ network.val === '' ? 'liquid' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1">
<img src="./resources/liquid-logo.png" style="width: 25px; height: 25px;" class="mr-1">
</button>
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
<a href="https://mempool.space" ngbDropdownItem class="mainnet"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</a>
@@ -21,13 +20,12 @@
<a href="https://mempool.space/testnet" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</a>
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
<a href="https://bisq.markets" ngbDropdownItem class="mainnet"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</a>
<button ngbDropdownItem class="liquid" [class.active]="network.val === 'liquid'" routerLink="/"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
<button ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquidtestnet'" routerLink="/testnet"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</button>
<button ngbDropdownItem class="liquid active" routerLink="/"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
</div>
</div>
<div class="navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav {{ network.val }}">
<ul class="navbar-nav liquid">
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
<a class="nav-link" [routerLink]="['/' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" i18n-title="master-page.dashboard" title="Dashboard"></fa-icon></a>
</li>
@@ -43,7 +41,7 @@
</li>
-->
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/assets' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
<a class="nav-link" [routerLink]="['/assets']" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
</li>
<li [hidden]="isMobile" class="nav-item mr-2" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/docs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="master-page.docs" title="Docs"></fa-icon></a>
@@ -62,4 +60,3 @@
<router-outlet></router-outlet>
<br>
</ng-container>

View File

@@ -102,10 +102,6 @@ nav {
background-color: #116761;
}
.liquidtestnet.active {
background-color: #494a4a;
}
.testnet.active {
background-color: #1d486f;
}

View File

@@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { Env, StateService } from '../../services/state.service';
import { merge, Observable, of} from 'rxjs';
import { Observable} from 'rxjs';
@Component({
selector: 'app-liquid-master-page',
@@ -13,7 +13,6 @@ export class LiquidMasterPageComponent implements OnInit {
navCollapsed = false;
isMobile = window.innerWidth <= 767.98;
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
network$: Observable<string>;
constructor(
private stateService: StateService,
@@ -22,7 +21,6 @@ export class LiquidMasterPageComponent implements OnInit {
ngOnInit() {
this.env = this.stateService.env;
this.connectionState$ = this.stateService.connectionState$;
this.network$ = merge(of(''), this.stateService.networkChanged$);
}
collapse(): void {

View File

@@ -11,7 +11,7 @@
</ng-container>
</a>
<div (window:resize)="onResize($event)" ngbDropdown class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
<div (window:resize)="onResize($event)" ngbDropdown class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED">
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
<img src="./resources/{{ network.val === '' ? 'bitcoin' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1">
</button>
@@ -24,8 +24,6 @@
<button ngbDropdownItem *ngIf="env.BISQ_ENABLED && !env.OFFICIAL_MEMPOOL_SPACE" class="bisq" [class.active]="network.val === 'bisq'" routerLink="/bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
<a href="https://liquid.network" ngbDropdownItem *ngIf="env.LIQUID_ENABLED && env.OFFICIAL_MEMPOOL_SPACE" class="liquid" [class.active]="network.val === 'liquid'"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
<button ngbDropdownItem *ngIf="env.LIQUID_ENABLED && !env.OFFICIAL_MEMPOOL_SPACE" class="liquid" [class.active]="network.val === 'liquid'" routerLink="/liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
<a href="https://liquid.network/testnet" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED && env.OFFICIAL_MEMPOOL_SPACE" class="liquidtestnet" [class.active]="network.val === 'liquid'"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</a>
<button ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED && !env.OFFICIAL_MEMPOOL_SPACE" class="liquidtestnet" [class.active]="network.val === 'liquidtestnet'" routerLink="/liquidtestnet"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</button>
</div>
</div>
@@ -56,8 +54,8 @@
<a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon></a>
</li>
</ng-template>
<li *ngIf="network.val === 'liquid' || network.val === 'liquidtestnet'" class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/assets' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
<li *ngIf="network.val === 'liquid'" class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/liquid/assets']" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
</li>
<li class="nav-item" routerLinkActive="active">
<a class="nav-link" [routerLink]="['/docs' | relativeUrl ]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="documentation.title" title="Documentation"></fa-icon></a>

View File

@@ -110,10 +110,6 @@ nav {
background-color: #116761;
}
.liquidtestnet.active {
background-color: #494a4a;
}
.testnet.active {
background-color: #1d486f;
}

View File

@@ -19,7 +19,7 @@
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }} transactions</ng-template>
</div>
<div class="time-difference" *ngIf="projectedBlock.blockVSize <= stateService.blockVSize; else mergedBlock">
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="timeDiffMainnet">
<ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeDiffMainnet">
<app-time-until [time]="(1 * i) + now + 61000" [fastRender]="false" [fixedRender]="true"></app-time-until>
</ng-template>
<ng-template #timeDiffMainnet>

View File

@@ -6,13 +6,11 @@ import { Router } from '@angular/router';
import { take, map, switchMap } from 'rxjs/operators';
import { feeLevels, mempoolFeeColors } from 'src/app/app.constants';
import { specialBlocks } from 'src/app/app.constants';
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
@Component({
selector: 'app-mempool-blocks',
templateUrl: './mempool-blocks.component.html',
styleUrls: ['./mempool-blocks.component.scss'],
providers: [RelativeUrlPipe],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MempoolBlocksComponent implements OnInit, OnDestroy {
@@ -54,11 +52,10 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
private router: Router,
public stateService: StateService,
private cd: ChangeDetectorRef,
private relativeUrlPipe: RelativeUrlPipe,
) { }
ngOnInit() {
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
if (this.stateService.network === 'liquid') {
this.feeRounding = '1.0-1';
}
this.mempoolEmptyBlocks.forEach((b) => {
@@ -169,19 +166,19 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
if (event.key === 'ArrowRight') {
if (this.mempoolBlocks[this.markIndex - 1]) {
this.router.navigate([this.relativeUrlPipe.transform('mempool-block/'), this.markIndex - 1]);
this.router.navigate([(this.network ? '/' + this.network : '') + '/mempool-block/', this.markIndex - 1]);
} else {
this.stateService.blocks$
.pipe(take(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT))
.subscribe(([block]) => {
if (this.stateService.latestBlockHeight === block.height) {
this.router.navigate([this.relativeUrlPipe.transform('/block/'), block.id], { state: { data: { block } }});
this.router.navigate([(this.network ? '/' + this.network : '') + '/block/', block.id], { state: { data: { block } }});
}
});
}
} else if (event.key === 'ArrowLeft') {
if (this.mempoolBlocks[this.markIndex + 1]) {
this.router.navigate([this.relativeUrlPipe.transform('/mempool-block/'), this.markIndex + 1]);
this.router.navigate([(this.network ? '/' + this.network : '') + '/mempool-block/', this.markIndex + 1]);
}
}
});

View File

@@ -371,7 +371,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
this.feeLimitIndex = i;
}
if (feeLevels[i] <= this.limitFee) {
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
if (this.stateService.network === 'liquid') {
this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)} - ${(feeLevels[i + 1] / 10).toFixed(1)}`);
} else {
this.feeLevelsOrdered.push(`${feeLevels[i]} - ${feeLevels[i + 1]}`);

View File

@@ -7,13 +7,11 @@ import { Observable, of, Subject, merge } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, filter, catchError, map } from 'rxjs/operators';
import { ElectrsApiService } from 'src/app/services/electrs-api.service';
import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap';
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
@Component({
selector: 'app-search-form',
templateUrl: './search-form.component.html',
styleUrls: ['./search-form.component.scss'],
providers: [RelativeUrlPipe],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SearchFormComponent implements OnInit {
@@ -40,7 +38,6 @@ export class SearchFormComponent implements OnInit {
private assetsService: AssetsService,
private stateService: StateService,
private electrsApiService: ElectrsApiService,
private relativeUrlPipe: RelativeUrlPipe,
) { }
ngOnInit() {
@@ -51,7 +48,7 @@ export class SearchFormComponent implements OnInit {
searchText: ['', Validators.required],
});
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
this.assetsService.getAssetsMinimalJson$
.subscribe((assets) => {
this.assets = assets;
@@ -104,7 +101,7 @@ export class SearchFormComponent implements OnInit {
this.navigate('/block/', searchText);
} else if (this.regexTransaction.test(searchText)) {
const matches = this.regexTransaction.exec(searchText);
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
if (this.assets[matches[1]]) {
this.navigate('/asset/', matches[1]);
}
@@ -128,7 +125,7 @@ export class SearchFormComponent implements OnInit {
}
navigate(url: string, searchText: string, extras?: any) {
this.router.navigate([this.relativeUrlPipe.transform(url), searchText], extras);
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + url, searchText], extras);
this.searchTriggered.emit();
this.searchForm.setValue({
searchText: '',

View File

@@ -117,7 +117,7 @@
</ng-template>
<ng-template [ngIf]="paymentForm.get('method').value === 'lbtc' || paymentForm.get('method').value === 'tlbtc'">
<ng-template [ngIf]="paymentForm.get('method').value === 'lbtc'">
<div class="qr-wrapper">
<a [href]="bypassSecurityTrustUrl('liquidnetwork:' + donationObj.addresses.LBTC + '?amount=' + donationObj.amount + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d')" target="_blank">

View File

@@ -41,11 +41,17 @@
</button>
<div class="dropdown-fees" ngbDropdownMenu aria-labelledby="dropdownFees">
<ul>
<ng-template ngFor let-feeData let-i="index" [ngForOf]="feeLevelDropdownData">
<ng-template [ngIf]="feeData.fee <= 400">
<li (click)="filterFeeIndex = feeData.fee" [class]="filterFeeIndex > feeData.fee ? 'inactive' : ''">
<span class="square" [ngStyle]="{'backgroundColor': feeData.color}"></span>
<span class="fee-text">{{ feeData.range }}</span>
<ng-template ngFor let-fee let-i="index" [ngForOf]="feeLevels">
<ng-template [ngIf]="fee <= 400">
<li (click)="filterFees(fee)" [class]="filterFeeIndex > fee ? 'inactive' : ''">
<ng-template [ngIf]="inverted">
<span class="square" [ngStyle]="{'backgroundColor': chartColors[i]}"></span>
<span class="fee-text" >{{feeLevels[i]}} - {{ feeLevels[i + 1] }}</span>
</ng-template>
<ng-template [ngIf]="!inverted">
<span class="square" [ngStyle]="{'backgroundColor': chartColors[i - 1]}"></span>
<span class="fee-text" >{{feeLevels[i]}} - {{ feeLevels[i - 1] }}</span>
</ng-template>
</li>
</ng-template>
</ng-template>

View File

@@ -37,7 +37,6 @@ export class StatisticsComponent implements OnInit {
radioGroupForm: FormGroup;
graphWindowPreference: string;
inverted: boolean;
feeLevelDropdownData = [];
constructor(
@Inject(LOCALE_ID) private locale: string,
@@ -52,10 +51,19 @@ export class StatisticsComponent implements OnInit {
ngOnInit() {
this.inverted = this.storageService.getValue('inverted-graph') === 'true';
this.setFeeLevelDropdownData();
if (!this.inverted) {
this.feeLevels = [...feeLevels].reverse();
this.chartColors = [...chartColors].reverse();
}
this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`);
this.stateService.networkChanged$.subscribe((network) => this.network = network);
this.graphWindowPreference = this.storageService.getValue('graphWindowPreference') ? this.storageService.getValue('graphWindowPreference').trim() : '2h';
const isMobile = window.innerWidth <= 767.98;
let labelHops = isMobile ? 48 : 24;
if (isMobile) {
labelHops = 96;
}
this.radioGroupForm = this.formBuilder.group({
dateSpan: this.graphWindowPreference
@@ -139,27 +147,11 @@ export class StatisticsComponent implements OnInit {
document.location.reload();
}
setFeeLevelDropdownData() {
let _feeLevels = feeLevels
let _chartColors = chartColors;
if (!this.inverted) {
_feeLevels = [...feeLevels].reverse();
_chartColors = [...chartColors].reverse();
}
_feeLevels.forEach((fee, i) => {
if (this.inverted) {
this.feeLevelDropdownData.push({
fee: fee,
range: this.stateService.isLiquid() ? `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[i + 1] / 10).toFixed(1)}` : `${_feeLevels[i]} - ${_feeLevels[i + 1]}`,
color: _chartColors[i],
});
} else {
this.feeLevelDropdownData.push({
fee: fee,
range: this.stateService.isLiquid() ? `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[i - 1] / 10).toFixed(1)}` : `${_feeLevels[i]} - ${_feeLevels[i - 1]}`,
color: _chartColors[i - 1],
});
}
})
filterFees(index: number) {
this.filterFeeIndex = index;
}
filterClick() {
this.dropDownOpen = !this.dropDownOpen;
}
}

View File

@@ -66,7 +66,7 @@
<td><app-time-span [time]="tx.status.block_time - transactionTime" [fastRender]="true"></app-time-span></td>
</tr>
</ng-template>
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
<tr *ngIf="network !== 'liquid'">
<td class="td-width" i18n="transaction.features|Transaction features">Features</td>
<td>
<app-tx-features [tx]="tx"></app-tx-features>
@@ -114,7 +114,7 @@
<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' || network === 'liquidtestnet'" [ngIfElse]="timeEstimateDefault">
<ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeEstimateDefault">
<app-time-until [time]="(60 * 1000 * txInBlockIndex) + now" [fastRender]="false" [fixedRender]="true"></app-time-until>
</ng-template>
<ng-template #timeEstimateDefault>
@@ -124,7 +124,7 @@
</ng-template>
</td>
</tr>
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
<tr *ngIf="network !== 'liquid'">
<td class="td-width" i18n="transaction.features|Transaction Features">Features</td>
<td>
<app-tx-features [tx]="tx"></app-tx-features>

View File

@@ -159,7 +159,7 @@ export class TransactionComponent implements OnInit, OnDestroy {
);
}),
switchMap((tx) => {
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
return from(this.liquidUnblinding.checkUnblindedTx(tx))
.pipe(
catchError((error) => {

View File

@@ -48,7 +48,7 @@
</td>
<td>
<div [ngSwitch]="true">
<ng-container *ngSwitchCase="vin.is_coinbase"><span i18n="transactions-list.coinbase">Coinbase</span><ng-template [ngIf]="network !== 'liquid' && network !== 'liquidtestnet'">&nbsp;<span i18n="transactions-list.newly-generated-coins">(Newly Generated Coins)</span></ng-template><br /><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii"><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></a></ng-container>
<ng-container *ngSwitchCase="vin.is_coinbase"><span i18n="transactions-list.coinbase">Coinbase</span><ng-template [ngIf]="network !== 'liquid'">&nbsp;<span i18n="transactions-list.newly-generated-coins">(Newly Generated Coins)</span></ng-template><br /><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii"><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></a></ng-container>
<ng-container *ngSwitchCase="vin.is_pegin">
<span i18n="transactions-list.peg-in">Peg-in</span>
</ng-container>
@@ -56,18 +56,13 @@
<span>P2PK</span>
</ng-container>
<ng-container *ngSwitchDefault>
<ng-template [ngIf]="!vin.prevout" [ngIfElse]="defaultAddress">
<span>{{ vin.issuance ? 'Issuance' : 'UNKNOWN' }}</span>
</ng-template>
<ng-template #defaultAddress>
<a [routerLink]="['/address/' | relativeUrl, vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
<span class="d-block d-lg-none">{{ vin.prevout.scriptpubkey_address | shortenString : 16 }}</span>
<span class="d-none d-lg-block">{{ vin.prevout.scriptpubkey_address | shortenString : 35 }}</span>
</a>
<div>
<app-address-labels [vin]="vin"></app-address-labels>
</div>
</ng-template>
<a [routerLink]="['/address/' | relativeUrl, vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
<span class="d-block d-lg-none">{{ vin.prevout.scriptpubkey_address | shortenString : 16 }}</span>
<span class="d-none d-lg-block">{{ vin.prevout.scriptpubkey_address | shortenString : 35 }}</span>
</a>
<div>
<app-address-labels [vin]="vin"></app-address-labels>
</div>
</ng-container>
</div>
</td>
@@ -249,7 +244,7 @@
&nbsp;
</span>
<button type="button" class="btn btn-sm btn-primary mt-2" (click)="switchCurrency()">
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="defaultAmount" i18n="shared.confidential">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>

View File

@@ -15,7 +15,7 @@ import { map } from 'rxjs/operators';
})
export class TransactionsListComponent implements OnInit, OnChanges {
network = '';
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
nativeAssetId = environment.nativeAssetId;
displayDetails = false;
@Input() transactions: Transaction[];
@@ -41,7 +41,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
this.latestBlock$ = this.stateService.blocks$.pipe(map(([block]) => block));
this.stateService.networkChanged$.subscribe((network) => this.network = network);
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
this.assetsService.getAssetsMinimalJson$.subscribe((assets) => {
this.assetsMinimal = assets;
});
@@ -99,7 +99,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
}
switchCurrency() {
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
if (this.network === 'liquid') {
return;
}
const oldvalue = !this.stateService.viewFiat$.value;

View File

@@ -2,7 +2,7 @@
<div class="container-xl dashboard-container">
<div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
<ng-template [ngIf]="collapseLevel === 'three'" [ngIfElse]="expanded">
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid'">
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
<div class="card">
<div class="card-body">
@@ -10,7 +10,7 @@
</div>
</div>
</div>
<div class="col" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
<div class="col" *ngIf="(network$ | async) !== 'liquid'">
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
</div>
<div class="col">
@@ -29,7 +29,7 @@
</div>
</ng-template>
<ng-template #expanded>
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid'">
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
<div class="card">
<div class="card-body">
@@ -37,7 +37,7 @@
</div>
</div>
</div>
<div class="col" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
<div class="col" *ngIf="(network$ | async) !== 'liquid'">
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
</div>
<div class="col">
@@ -125,7 +125,7 @@
<tbody>
<tr *ngFor="let transaction of transactions$ | async; let i = index;">
<td class="table-cell-txid"><a [routerLink]="['/tx' | relativeUrl, transaction.txid]">{{ transaction.txid | shortenString : 10 }}</a></td>
<td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
<td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
<td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
<td class="table-cell-fees">{{ transaction.fee / transaction.vsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
</tr>

View File

@@ -262,7 +262,7 @@ export class DashboardComponent implements OnInit {
share(),
);
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
if (this.stateService.network === 'liquid') {
this.liquidPegsMonth$ = this.apiService.listLiquidPegsMonth$()
.pipe(
map((pegs) => {

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map, shareReplay, switchMap } from 'rxjs/operators';
import { shareReplay } from 'rxjs/operators';
import { StateService } from './state.service';
@Injectable({
@@ -21,23 +21,8 @@ export class AssetsService {
apiBaseUrl = this.stateService.env.NGINX_PROTOCOL + '://' + this.stateService.env.NGINX_HOSTNAME + ':' + this.stateService.env.NGINX_PORT;
}
this.getAssetsJson$ = this.stateService.networkChanged$
.pipe(
switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.json`)),
shareReplay(1),
);
this.getAssetsMinimalJson$ = this.stateService.networkChanged$
.pipe(
switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.minimal.json`)),
map((assetsMinimal) => {
if (this.stateService.network === 'liquidtestnet') {
// Hard coding the Liquid Testnet native asset
assetsMinimal['144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'] = [null, "tL-BTC", "Test Liquid Bitcoin", 8];
}
return assetsMinimal;
}),
shareReplay(1),
);
this.getMiningPools$ = this.httpClient.get(apiBaseUrl + '/resources/pools.json').pipe(shareReplay(1));
this.getAssetsJson$ = this.httpClient.get(apiBaseUrl + '/resources/assets.json').pipe(shareReplay());
this.getAssetsMinimalJson$ = this.httpClient.get(apiBaseUrl + '/resources/assets.minimal.json').pipe(shareReplay());
this.getMiningPools$ = this.httpClient.get(apiBaseUrl + '/resources/pools.json').pipe(shareReplay());
}
}

View File

@@ -27,14 +27,8 @@ export class SeoService {
}
getTitle(): string {
if (this.network === 'testnet')
return 'mempool - Bitcoin Testnet';
if (this.network === 'signet')
return 'mempool - Bitcoin Signet';
if (this.network === 'liquid')
return 'mempool - Liquid Network';
if (this.network === 'liquidtestnet')
return 'mempool - Liquid Testnet';
if (this.network === 'bisq')
return 'mempool - Bisq Markets';
return 'mempool - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer';

View File

@@ -19,7 +19,6 @@ export interface Env {
TESTNET_ENABLED: boolean;
SIGNET_ENABLED: boolean;
LIQUID_ENABLED: boolean;
LIQUID_TESTNET_ENABLED: boolean;
BISQ_ENABLED: boolean;
BISQ_SEPARATE_BACKEND: boolean;
ITEMS_PER_PAGE: number;
@@ -39,7 +38,6 @@ const defaultEnv: Env = {
'TESTNET_ENABLED': false,
'SIGNET_ENABLED': false,
'LIQUID_ENABLED': false,
'LIQUID_TESTNET_ENABLED': false,
'BASE_MODULE': 'mempool',
'BISQ_ENABLED': false,
'BISQ_SEPARATE_BACKEND': false,
@@ -118,7 +116,7 @@ export class StateService {
this.blocks$ = new ReplaySubject<[Block, boolean]>(this.env.KEEP_BLOCKS_AMOUNT);
if (this.env.BASE_MODULE === 'bisq') {
if (this.env.BASE_MODULE !== 'mempool') {
this.network = this.env.BASE_MODULE;
this.networkChanged$.next(this.env.BASE_MODULE);
}
@@ -127,10 +125,10 @@ export class StateService {
}
setNetworkBasedonUrl(url: string) {
if (this.env.BASE_MODULE !== 'mempool' && this.env.BASE_MODULE !== 'liquid') {
if (this.env.BASE_MODULE !== 'mempool') {
return;
}
const networkMatches = url.match(/\/(bisq|testnet|liquidtestnet|liquid|signet)/);
const networkMatches = url.match(/\/(bisq|testnet|liquid|signet)/);
switch (networkMatches && networkMatches[1]) {
case 'liquid':
if (this.network !== 'liquid') {
@@ -138,12 +136,6 @@ export class StateService {
this.networkChanged$.next('liquid');
}
return;
case 'liquidtestnet':
if (this.network !== 'liquidtestnet') {
this.network = 'liquidtestnet';
this.networkChanged$.next('liquidtestnet');
}
return;
case 'signet':
if (this.network !== 'signet') {
this.network = 'signet';
@@ -152,13 +144,8 @@ export class StateService {
return;
case 'testnet':
if (this.network !== 'testnet') {
if (this.env.BASE_MODULE === 'liquid') {
this.network = 'liquidtestnet';
this.networkChanged$.next('liquidtestnet');
} else {
this.network = 'testnet';
this.networkChanged$.next('testnet');
}
this.network = 'testnet';
this.networkChanged$.next('testnet');
}
return;
case 'bisq':
@@ -168,12 +155,7 @@ export class StateService {
}
return;
default:
if (this.env.BASE_MODULE !== 'mempool') {
if (this.network !== this.env.BASE_MODULE) {
this.network = this.env.BASE_MODULE;
this.networkChanged$.next(this.env.BASE_MODULE);
}
} else if (this.network !== '') {
if (this.network !== '') {
this.network = '';
this.networkChanged$.next('');
}
@@ -200,8 +182,4 @@ export class StateService {
setBlockScrollingInProgress(value: boolean) {
this.blockScrolling$.next(value);
}
isLiquid() {
return this.network === 'liquid' || this.network === 'liquidtestnet';
}
}

View File

@@ -11,13 +11,10 @@ export class RelativeUrlPipe implements PipeTransform {
) { }
transform(value: string): string {
let network = this.stateService.network;
if (this.stateService.env.BASE_MODULE === 'liquid' && network === 'liquidtestnet') {
network = 'testnet';
} else if (this.stateService.env.BASE_MODULE !== 'mempool') {
network = '';
if (this.stateService.env.BASE_MODULE !== 'mempool') {
return '/' + value;
}
return (network ? '/' + network : '') + value;
return (this.stateService.network ? '/' + this.stateService.network : '') + value;
}
}

View File

@@ -1,5 +1,4 @@
export const environment = {
production: true,
nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
nativeTestAssetId: '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49',
};

View File

@@ -5,7 +5,6 @@
export const environment = {
production: false,
nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
nativeTestAssetId: '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49',
};
/*

View File

@@ -5,7 +5,7 @@
<title>mempool - Bisq Markets</title>
<base href="/">
<meta name="description" content="The Mempool Open Source Project™ - our self-hosted explorer for the Bisq Network.">
<meta name="description" content="An open-source explorer developed for the Bisq community.">
<meta property="og:image" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
<meta property="og:image:type" content="image/jpeg" />
@@ -13,8 +13,8 @@
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:site" content="https://bisq.markets/">
<meta property="twitter:creator" content="@bisq_network">
<meta property="twitter:title" content="The Mempool Open Source Project™">
<meta property="twitter:description" content="Our self-hosted markets explorer for the Bisq community.">
<meta property="twitter:title" content="mempool - Bisq Markets">
<meta property="twitter:description" content="An open-source explorer developed for the Bisq community.">
<meta property="twitter:image:src" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
<meta property="twitter:domain" content="bisq.markets">

View File

@@ -5,7 +5,7 @@
<title>mempool - Liquid Network</title>
<base href="/">
<meta name="description" content="The Mempool Open Source Project™ - our self-hosted explorer for the Liquid Network.">
<meta name="description" content="An open-source explorer developed for the Liquid Network.">
<meta property="og:image" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1000" />
@@ -13,8 +13,8 @@
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:site" content="@mempool">
<meta property="twitter:creator" content="@mempool">
<meta property="twitter:title" content="The Mempool Open Source Project™">
<meta property="twitter:description" content="Our self-hosted network explorer for the Liquid community.">
<meta property="twitter:title" content="mempool - Liquid Network">
<meta property="twitter:description" content="An open-source explorer developed for the Liquid Network.">
<meta property="twitter:image:src" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
<meta property="twitter:domain" content="liquid.network">

View File

@@ -5,7 +5,7 @@
<title>mempool - Bitcoin Explorer</title>
<base href="/">
<meta name="description" content="The Mempool Open Source Project™ - our self-hosted explorer for the Bitcoin community." />
<meta name="description" content="An open-source explorer developed for the Bitcoin community, focusing on the emerging transaction fee market to help our transition into a multi-layer ecosystem." />
<meta property="og:image" content="https://mempool.space/resources/mempool-space-preview.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1000" />
@@ -13,8 +13,8 @@
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:site" content="@mempool">
<meta property="twitter:creator" content="@mempool">
<meta property="twitter:title" content="The Mempool Open Source Project™">
<meta property="twitter:description" content="Our self-hosted mempool explorer for the Bitcoin community." />
<meta property="twitter:title" content="mempool">
<meta property="twitter:description" content="An open-source explorer developed for the Bitcoin community, focusing on the transition into a multi-layer ecosystem." />
<meta property="twitter:image:src" content="https://mempool.space/resources/mempool-space-preview.png" />
<meta property="twitter:domain" content="mempool.space">

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,17 +0,0 @@
<svg width="897" height="1072" viewBox="0 0 897 1072" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M304.742 112.004L448.742 29.7188V157.719L304.742 240.004V112.004Z" fill="#40607D"/>
<path d="M616.742 224L592.742 240V112L616.742 95.9999V224Z" fill="#40607D"/>
<path d="M52.6641 256.045L192.744 176V304L164.728 320.009L52.6641 256.045Z" fill="#40607D"/>
<path d="M168.742 480L192.742 464V411.789L280.742 462.736V416L304.742 400L448.742 482.4V208L192.742 356.21V336L168.742 352V480Z" fill="#40607D"/>
<path d="M728.742 352L896.741 256V699.935C896.741 771.706 858.284 837.975 795.969 873.583L448.742 1072V511.999L616.742 416V543.999L728.742 480V352Z" fill="#40607D"/>
<path d="M448.742 157.719L592.742 240.004V112.004L448.742 29.7188V157.719Z" fill="#6891AA"/>
<path d="M304.742 240L280.742 224V95.9999L304.742 112V240Z" fill="#6891AA"/>
<path d="M168.742 352L0.742188 256V699.935C0.742188 771.706 39.1994 837.975 101.514 873.583L448.742 1072V511.999L280.742 416V543.999L168.742 480V352Z" fill="#6891AA"/>
<path d="M704.741 464L728.741 480V352L704.741 336V356.21L448.742 208V482.4L592.742 400L616.742 416V462.736L704.741 411.789V464Z" fill="#6891AA"/>
<path d="M732.757 320.009L704.741 304V176L844.821 256.045L732.757 320.009Z" fill="#6891AA"/>
<path d="M448.742 29.6L592.742 112L616.742 95.9999L448.742 0L280.742 95.9999L304.742 112L448.742 29.6Z" fill="#A2BECE"/>
<path d="M280.742 224L304.742 240L448.742 157.719L592.742 240.004L616.742 224L704.741 274.285V304L732.757 320.009L844.901 256L704.741 176L728.741 160L896.741 256L728.741 352L704.741 336V356.21L448.742 208L192.742 356.21V336L168.742 352L0.742188 256L168.742 160L192.742 176L52.5821 256L164.728 320.009L192.744 304V274.284L280.742 224Z" fill="#A2BECE"/>
<path d="M592.742 400L616.742 416L448.742 511.999L280.742 416L304.742 400L448.742 482.4L592.742 400Z" fill="#A2BECE"/>
<path d="M192.742 411.789L280.742 462.736V543.999L168.742 480L192.742 464V411.789Z" fill="#A2BECE"/>
<path d="M728.741 480L616.742 543.999V462.736L704.741 411.789V464L728.741 480Z" fill="#A2BECE"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -100,10 +100,6 @@ body {
background-color: #6f1d5d !important;
}
.navbar-nav.liquidtestnet > .active {
background-color: #494a4a !important;
}
.form-control {
color: #495057;
}

View File

@@ -42,17 +42,9 @@ if (configContent.BASE_MODULE && configContent.BASE_MODULE === 'liquid') {
assetsMinimalJsonUrl = 'https://raw.githubusercontent.com/Blockstream/asset_registry_db/master/index.minimal.json';
}
const testnetAssetsJsonUrl = 'https://raw.githubusercontent.com/Blockstream/asset_registry_testnet_db/master/index.json';
const testnetAssetsMinimalJsonUrl = 'https://raw.githubusercontent.com/Blockstream/asset_registry_testnet_db/master/index.minimal.json';
console.log('Downloading assets');
download(PATH + 'assets.json', assetsJsonUrl);
console.log('Downloading assets minimal');
download(PATH + 'assets.minimal.json', assetsMinimalJsonUrl);
console.log('Downloading mining pools info');
download(PATH + 'pools.json', poolsJsonUrl);
console.log('Downloading testnet assets');
download(PATH + 'assets-testnet.json', testnetAssetsJsonUrl);
console.log('Downloading testnet assets minimal');
download(PATH + 'assets-testnet.minimal.json', testnetAssetsMinimalJsonUrl);

View File

@@ -1,88 +1,80 @@
# mempool enterprise production instance
# mempool.space v2 production website hosting
These instructions are for setting up a serious production mempool website for Bitcoin mainnet, testnet, signet, Liquid mainnet and testnet, and Bisq. For home users, you should use one-click installation methods instead, and for advanced manual deployments of mainnet only see the top-level installation instructions.
These instructions are for setting up a serious production mempool website for Mainnet, Testnet, and Liquid. For home users, follow the main instructions instead.
### Server Hardware
Mempool V2 is powered by blockstream/electrs, which is a beast. I recommend a beefy server:
Mempool V2 is powered by electrs, which is a beast. I recommend a beefy server:
* 20C CPU (more is better)
* 16C CPU (more is better)
* 64G RAM (more is better)
* 4TB SSD (NVMe is better)
* 2TB SSD (NVMe is better)
### HDD vs SSD vs NVMe
If you don't have a fast SSD or NVMe backed disk, that's fine. What you do is, go online and buy some fast new NVMe drives and wait for them to arrive. After you install them, throw away your old HDDs and then proceed with the rest of this guide.
## FreeBSD 13
## FreeBSD 12
The mempool.space site is powered by FreeBSD with ZFS root and ARC cache for maximum performance. Linux probably works fine too, but why settle?
### Filesystem
For maximum performance, I use 2x 2TB NVMe SSDs in a RAID 0 using ZFS with lots of RAM for the ARC L2 cache.
For maximum performance, I use 2x 1TB NVMe SSDs in a RAID 0 using ZFS with lots of RAM for the ARC L2 cache.
```
% zpool list -v
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
nvm 3.62T 1.25T 2.38T - - 2% 34% 1.00x ONLINE -
nvd0p3 1.81T 629G 1.20T - - 2% 33.9% - ONLINE
nvd1p3 1.81T 646G 1.18T - - 2% 34.8% - ONLINE
# zpool list -v nvmraid
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
nvmraid 1.81T 1.04T 787G - - 0% 57% 1.00x ONLINE -
nvd0 928G 535G 393G - - 0% 57%
nvd1 928G 534G 394G - - 0% 57%
```
For maximum flexibility of configuration, I recommend partitions separately for each data folder:
For maximum flexibility of configuration, I configure the partitions separately for each data folder:
```
Filesystem Size Used Avail Capacity Mounted on
nvm/bisq 766G 1.1G 765G 0% /bisq
nvm/bitcoin 766G 648M 765G 0% /bitcoin
nvm/bitcoin/blocks 1.1T 375G 765G 33% /bitcoin/blocks
nvm/bitcoin/chainstate 770G 4.5G 765G 1% /bitcoin/chainstate
nvm/bitcoin/electrs 772G 7.3G 765G 1% /bitcoin/electrs
nvm/bitcoin/indexes 799G 34G 765G 4% /bitcoin/indexes
nvm/bitcoin/testnet3 765G 5.0M 765G 0% /bitcoin/testnet3
nvm/bitcoin/testnet3/blocks 786G 21G 765G 3% /bitcoin/testnet3/blocks
nvm/bitcoin/testnet3/chainstate 766G 1.1G 765G 0% /bitcoin/testnet3/chainstate
nvm/bitcoin/testnet3/indexes 768G 2.9G 765G 0% /bitcoin/testnet3/indexes
nvm/electrs 765G 128K 765G 0% /electrs
nvm/electrs/liquid 765G 104K 765G 0% /electrs/liquid
nvm/electrs/liquid/cache 765G 7.8M 765G 0% /electrs/liquid/newindex/cache
nvm/electrs/liquid/history 766G 886M 765G 0% /electrs/liquid/newindex/history
nvm/electrs/liquid/txstore 775G 10G 765G 1% /electrs/liquid/newindex/txstore
nvm/electrs/liquidtestnet 765G 112K 765G 0% /electrs/liquidtestnet
nvm/electrs/liquidtestnet/cache 765G 96K 765G 0% /electrs/liquidtestnet/newindex/cache
nvm/electrs/liquidtestnet/history 765G 96K 765G 0% /electrs/liquidtestnet/newindex/history
nvm/electrs/liquidtestnet/txstore 765G 96K 765G 0% /electrs/liquidtestnet/newindex/txstore
nvm/electrs/mainnet 765G 112K 765G 0% /electrs/mainnet
nvm/electrs/mainnet/cache 765G 4.4M 765G 0% /electrs/mainnet/newindex/cache
nvm/electrs/mainnet/history 1.0T 300G 765G 28% /electrs/mainnet/newindex/history
nvm/electrs/mainnet/txstore 1.3T 530G 765G 41% /electrs/mainnet/newindex/txstore
nvm/electrs/signet 766G 522M 765G 0% /electrs/signet
nvm/electrs/testnet 765G 104K 765G 0% /electrs/testnet
nvm/electrs/testnet/cache 765G 1.6M 765G 0% /electrs/testnet/newindex/cache
nvm/electrs/testnet/history 784G 19G 765G 2% /electrs/testnet/newindex/history
nvm/electrs/testnet/txstore 803G 38G 765G 5% /electrs/testnet/newindex/txstore
nvm/elements 766G 927M 765G 0% /elements
nvm/elements/electrs 766G 716M 765G 0% /elements/electrs
nvm/elements/liquidv1 777G 11G 765G 1% /elements/liquidv1
nvm/mempool 789G 24G 765G 3% /mempool
nvm/mysql 766G 648M 765G 0% /mysql
tmpfs 1.0G 1.3M 1.0G 0% /var/cache/nginx
tmpfs 3.0G 1.9G 1.1G 63% /bisq/statsnode-data/btc_mainnet/db/json
nvmraid/mempool 732G 3.0G 729G 0% /mempool
nvmraid/mysql 730G 618M 729G 0% /mysql
nvmraid/bisq 729G 88K 729G 0% /bisq
nvmraid/elements 731G 1.8G 729G 0% /elements
nvmraid/elements/liquidv1 737G 7.2G 729G 1% /elements/liquidv1
nvmraid/elements/electrs 730G 434M 729G 0% /elements/electrs
nvmraid/bitcoin 730G 694M 729G 0% /bitcoin
nvmraid/bitcoin/chainstate 733G 3.9G 729G 1% /bitcoin/chainstate
nvmraid/bitcoin/indexes 757G 27G 729G 4% /bitcoin/indexes
nvmraid/bitcoin/electrs 730G 853M 729G 0% /bitcoin/electrs
nvmraid/bitcoin/blocks 1.0T 306G 729G 30% /bitcoin/blocks
nvmraid/bitcoin/testnet3 729G 13M 729G 0% /bitcoin/testnet3
nvmraid/bitcoin/testnet3/blocks 756G 26G 729G 3% /bitcoin/testnet3/blocks
nvmraid/bitcoin/testnet3/chainstate 731G 1.3G 729G 0% /bitcoin/testnet3/chainstate
nvmraid/bitcoin/testnet3/indexes 733G 3.8G 729G 1% /bitcoin/testnet3/indexes
nvmraid/electrs/liquid/cache 729G 39M 729G 0% /electrs/liquid/newindex/cache
nvmraid/electrs/liquid/history 730G 737M 729G 0% /electrs/liquid/newindex/history
nvmraid/electrs/liquid/txstore 736G 6.2G 729G 1% /electrs/liquid/newindex/txstore
nvmraid/electrs/mainnet/cache 729G 44M 729G 0% /electrs/mainnet/newindex/cache
nvmraid/electrs/mainnet/history 964G 234G 729G 24% /electrs/mainnet/newindex/history
nvmraid/electrs/mainnet/txstore 1.1T 392G 729G 35% /electrs/mainnet/newindex/txstore
nvmraid/electrs/testnet/cache 729G 40M 729G 0% /electrs/testnet/newindex/cache
nvmraid/electrs/testnet/history 747G 18G 729G 2% /electrs/testnet/newindex/history
nvmraid/electrs/testnet/txstore 764G 34G 729G 4% /electrs/testnet/newindex/txstore
```
### Build Dependencies
You'll probably need these:
```
pkg install -y zsh sudo git screen curl wget neovim rsync nginx openssl openssh-portable py38-pip py38-certbot-nginx boost-libs autoconf automake gmake gcc libevent libtool pkgconf mariadb105-server mariadb105-client
pkg install -y zsh sudo git screen vim-console curl wget neovim rsync
pkg install -y openssl openssh-portable open-vm-tools-nox11 py37-pip
pkg install -y boost-libs autoconf automake gmake gcc libevent libtool pkgconf
pkg install -y mariadb55-server mariadb55-client nginx py37-certbot-nginx npm
```
### NodeJS / npm
I recommend to build nodejs / npm from source using nvm:
```
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | zsh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | zsh
source $HOME/.zshrc
nvm install v16.10.0
nvm install node
nvm alias default node
```
@@ -115,18 +107,11 @@ DataDirectory /var/db/tor
DataDirectoryGroupReadable 1
HiddenServiceDir /var/db/tor/mempool
HiddenServicePort 80 127.0.0.1:81
HiddenServiceVersion 3
HiddenServiceDir /var/db/tor/bisq
HiddenServicePort 80 127.0.0.1:82
HiddenServiceVersion 3
HiddenServiceDir /var/db/tor/liquid
HiddenServicePort 80 127.0.0.1:83
HiddenServicePort 80 127.0.0.1:80
HiddenServiceVersion 3
```
### Bitcoin
Build [Bitcoin Core](https://github.com/bitcoin/bitcoin) from source. Alternatively, install the OS packages:
@@ -136,35 +121,25 @@ pkg install -y bitcoin-daemon bitcoin-utils
Configure your bitcoin.conf like this:
```
datadir=/bitcoin
server=1
txindex=1
daemon=1
listen=1
discover=1
par=16
dbcache=4096
maxmempool=1337
mempoolexpiry=999999
maxconnections=42
txindex=1
dbcache=3700
maxconnections=1337
onion=127.0.0.1:9050
rpcallowip=127.0.0.1
rpcuser=foo
rpcpassword=bar
rpcuser=0cd862dce678b830bd2aa36f10b9b6b2
rpcpassword=2d89d36cac4a13c87b5d19ef8f577e37
[main]
bind=127.0.0.1:8333
rpcbind=127.0.0.1:8332
whitelist=bloomfilter@127.0.0.1
[test]
daemon=1
bind=127.0.0.1:18333
rpcbind=127.0.0.1:18332
[signet]
daemon=1
bind=127.0.0.1:38333
rpcbind=127.0.0.1:38332
```
### Elements
@@ -183,39 +158,15 @@ Configure your elements.conf like this:
server=1
daemon=1
listen=1
rpcuser=foo
rpcpassword=bar
mainchainrpchost=127.0.0.1
mainchainrpcuser=foo
mainchainrpcpassword=bar
txindex=1
[liquidv1]
chain=liquidv1
rpcuser=liquiduser
rpcpassword=liquidpass
validatepegin=1
mainchainrpchost=127.0.0.1
mainchainrpcport=8332
[liquidtestnet]
validatepegin=0
anyonecanspendaremine=0
initialfreecoins=2100000000000000
con_dyna_deploy_start=0
con_max_block_sig_size=150
checkblockindex=0
fallbackfee=0.00000100
con_has_parent_chain=0
parentgenesisblockhash=NULL
pubkeyprefix=36
scriptprefix=19
blindedprefix=23
bech32_hrp=tex
blech32_hrp=tlq
pchmessagestart=410edd62
dynamic_epoch_length=1000
signblockscript=51210217e403ddb181872c32a0cd468c710040b2f53d8cac69f18dad07985ee37e9a7151ae
evbparams=dynafed:0:::
addnode=liquid-testnet.blockstream.com:18892
addnode=liquidtestnet.com:18891
addnode=liquid.network:18444
mainchainrpcuser=user
mainchainrpcpassword=pass
txindex=1
```
Start elementsd and wait for it to sync the Liquid blockchain.
@@ -229,42 +180,33 @@ cd electrs
git checkout new-index
```
You'll need one instance per network. Build and run them one at a time:
You'll need 3 instances, one for each network. Build one at a time:
```
./electrs-start-mainnet
./electrs-start-testnet
./electrs-start-signet
./electrs-start-liquid
./electrs-start-liquidtestnet
```
### MariaDB
Import historical mempool fee database snapshot:
Import historical mempool fee database snapshot, or the blank mariadb structure if none:
```
mysql -u root
create database mempool;
grant all on mempool.* to 'mempool'@'localhost' identified by 'mempool';
create database mempool_testnet;
grant all on mempool_testnet.* to 'mempool_testnet'@'localhost' identified by 'mempool_testnet';
create database mempool_signet;
grant all on mempool_signet.* to 'mempool_signet'@'localhost' identified by 'mempool_signet';
create database mempool_liquid;
grant all on mempool_liquid.* to 'mempool_liquid'@'localhost' identified by 'mempool_liquid';
create database mempool_liquidtestnet;
grant all on mempool_liquidtestnet.* to 'mempool_liquidtestnet'@'localhost' identified by 'mempool_liquidtestnet';
create database tmempool;
grant all on tmempool.* to 'tmempool'@'localhost' identified by 'tmempool';
create database lmempool;
grant all on lmempool.* to 'lmempool'@'localhost' identified by 'lmempool';
```
### Bisq
Build bisq-statsnode normally and run using options like this:
Then import
```
./bisq-statsnode --dumpBlockchainData=true --dumpStatistics=true
mysql -u mempool -p mempool < /mempool/mempool/mariadb-structure.sql
mysql -u tmempool -p tmempool < /mempool/mempool/mariadb-structure.sql
mysql -u lmempool -p lmempool < /mempool/mempool/mariadb-structure.sql
```
If bisq is happy, it should dump JSON files for Bisq Markets and BSQ data into /bisq that the mempool backend will use.
### Mempool
After all 3 electrs instances are fully indexed, install your 3 mempool nodes:
@@ -282,15 +224,13 @@ Finally, start your 3 mempool backends:
Get SSL certificate using certbot:
```
certbot --nginx -d mempool.ninja
certbot --nginx -d mempool.space
```
Make a symlink from /usr/local/etc/nginx/mempool to /mempool/mempool, and copy the nginx.conf and edit as necessary. You probably only need to edit the top-level nginx.conf file.
Install nginx.conf from this repo, edit as necessary:
```
cd /usr/local/etc/nginx
ln -s /mempool/mempool
cp /mempool/mempool/nginx.conf .
vi nginx.conf
cp nginx.conf /usr/local/etc/nginx/nginx.conf
vi /usr/local/etc/nginx/nginx.conf
```
Restart nginx
@@ -301,3 +241,4 @@ service nginx restart
### Done
Your site should look like https://mempool.space/
If it doesn't ask wiz on Keybase DM or Twitter for help.

View File

@@ -1,30 +0,0 @@
#!/usr/local/bin/zsh
cd "$HOME/electrs"
#source $HOME/.cargo/env
#export PATH=$HOME/.cargo/bin:$PATH
until false
do
# patch code for FreeBSD
if grep XBS5 "$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/sysconf-0.3.4/src/raw.rs" ; then
grep -v XBS5 $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/sysconf-0.3.4/src/raw.rs > /tmp/foo && \
mv /tmp/foo $HOME/.cargo/registry/src/github.com-1ecc6299db9ec823/sysconf-0.3.4/src/raw.rs
fi
cargo run \
--release \
--features liquid \
--bin electrs \
-- \
-vv \
--asset-db-path "$HOME/asset_registry_testnet_db" \
--address-search \
--cors '*' \
--db-dir /electrs \
--network liquidtestnet \
--daemon-dir $HOME \
--http-addr '[::]:3004' \
--cookie 'foo:bar' \
--precache-scripts $HOME/electrs/contrib/popular-scripts.txt
sleep 1
done

View File

@@ -1,39 +0,0 @@
{
"MEMPOOL": {
"NETWORK": "liquid",
"BACKEND": "esplora",
"HTTP_PORT": 8994,
"MINED_BLOCKS_CACHE": 144,
"SPAWN_CLUSTER_PROCS": 0,
"API_URL_PREFIX": "/api/v1/",
"WEBSOCKET_REFRESH_RATE_MS": 2000
},
"SYSLOG" : {
"MIN_PRIORITY": "debug"
},
"CORE_RPC": {
"PORT": 7040,
"USERNAME": "foo",
"PASSWORD": "bar"
},
"SECOND_CORE_RPC": {
"PORT": 8332,
"USERNAME": "foo",
"PASSWORD": "bar"
},
"ESPLORA": {
"REST_API_URL": "http://127.0.0.1:4004"
},
"DATABASE": {
"ENABLED": true,
"HOST": "127.0.0.1",
"PORT": 3306,
"USERNAME": "mempool_liquidtestnet",
"PASSWORD": "mempool_liquidtestnet",
"DATABASE": "mempool_liquidtestnet"
},
"STATISTICS": {
"ENABLED": true,
"TX_PER_SECOND_SAMPLE_PERIOD": 150
}
}

Some files were not shown because too many files have changed in this diff Show More