Merge branch 'master' into orangesurf/trademark-updates-2
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { MempoolBlockDelta, MempoolBlockDeltaCompressed, MempoolDeltaChange, TransactionCompressed, TransactionStripped } from "../interfaces/websocket.interface";
|
||||
|
||||
export function isMobile(): boolean {
|
||||
return (window.innerWidth <= 767.98);
|
||||
}
|
||||
@@ -152,4 +154,29 @@ export function seoDescriptionNetwork(network: string): string {
|
||||
return ' ' + network.charAt(0).toUpperCase() + network.slice(1);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
export function uncompressTx(tx: TransactionCompressed): TransactionStripped {
|
||||
return {
|
||||
txid: tx[0],
|
||||
fee: tx[1],
|
||||
vsize: tx[2],
|
||||
value: tx[3],
|
||||
rate: tx[4],
|
||||
flags: tx[5],
|
||||
acc: !!tx[6],
|
||||
};
|
||||
}
|
||||
|
||||
export function uncompressDeltaChange(delta: MempoolBlockDeltaCompressed): MempoolBlockDelta {
|
||||
return {
|
||||
added: delta.added.map(uncompressTx),
|
||||
removed: delta.removed,
|
||||
changed: delta.changed.map(tx => ({
|
||||
txid: tx[0],
|
||||
rate: tx[1],
|
||||
flags: tx[2],
|
||||
acc: !!tx[3],
|
||||
}))
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
<ng-container *ngIf="rateUnits$ | async as units">
|
||||
<ng-container *ngIf="units !== 'wu'">{{ fee / (weight / 4) | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></ng-container>
|
||||
<ng-container *ngIf="units === 'wu'">{{ fee / weight | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-weight-units|sat/WU">sat/WU</span></ng-container>
|
||||
<ng-container *ngIf="fee !== undefined; else noFee">
|
||||
<ng-container *ngIf="units !== 'wu'">{{ fee / (weight / 4) | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></ng-container>
|
||||
<ng-container *ngIf="units === 'wu'">{{ fee / weight | feeRounding:rounding }} <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-weight-units|sat/WU">sat/WU</span></ng-container>
|
||||
</ng-container>
|
||||
<ng-template #noFee>
|
||||
<ng-container *ngIf="units !== 'wu'">- <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></ng-container>
|
||||
<ng-container *ngIf="units === 'wu'">- <span *ngIf="showUnit" [class]="unitClass" [style]="unitStyle" i18n="shared.sat-weight-units|sat/WU">sat/WU</span></ng-container>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
@@ -8,7 +8,7 @@ import { StateService } from '../../../services/state.service';
|
||||
styleUrls: ['./fee-rate.component.scss']
|
||||
})
|
||||
export class FeeRateComponent implements OnInit {
|
||||
@Input() fee: number;
|
||||
@Input() fee: number | undefined;
|
||||
@Input() weight: number = 4;
|
||||
@Input() rounding: string = null;
|
||||
@Input() showUnit: boolean = true;
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<app-svg-images *ngIf="officialMempoolSpace" name="officialMempoolSpace" viewBox="0 0 500 126"></app-svg-images>
|
||||
<app-svg-images *ngIf="!officialMempoolSpace" name="mempoolSpace" viewBox="0 0 500 126"></app-svg-images>
|
||||
</div>
|
||||
<p class="d-block d-sm-none">
|
||||
<p class="explore-tagline-mobile">
|
||||
<ng-container i18n="@@7deec1c1520f06170e1f8e8ddfbe4532312f638f">Explore the full Bitcoin ecosystem</ng-container>
|
||||
<ng-template [ngIf]="locale.substr(0, 2) === 'en'"> ™</ng-template>
|
||||
<ng-template [ngIf]="locale.substr(0, 2) === 'en'">®</ng-template>
|
||||
</p>
|
||||
<div class="site-options float-right d-flex justify-content-center align-items-center" [class]="{'services': isServicesPage}">
|
||||
<div class="site-options language-selector d-flex justify-content-center align-items-center" [class]="{'services': isServicesPage}">
|
||||
<div class="selector">
|
||||
<app-language-selector></app-language-selector>
|
||||
</div>
|
||||
@@ -26,13 +26,13 @@
|
||||
<span *ngIf="!loggedIn" i18n="shared.sign-in">Sign In</span>
|
||||
</a>
|
||||
</div>
|
||||
<a *ngIf="servicesEnabled" class="btn btn-purple sponsor d-flex d-sm-none justify-content-center ml-auto mr-auto mt-3 mb-2" [routerLink]="['/login' | relativeUrl]">
|
||||
<a *ngIf="servicesEnabled" class="btn btn-purple sponsor d-flex d-sm-none justify-content-center ml-auto mr-auto mt-0 mb-2" [routerLink]="['/login' | relativeUrl]">
|
||||
<span *ngIf="loggedIn" i18n="shared.my-account">My Account</span>
|
||||
<span *ngIf="!loggedIn" i18n="shared.sign-in">Sign In</span>
|
||||
</a>
|
||||
<p class="d-none d-sm-block">
|
||||
<p class="explore-tagline-desktop">
|
||||
<ng-container i18n="@@7deec1c1520f06170e1f8e8ddfbe4532312f638f">Explore the full Bitcoin ecosystem</ng-container>
|
||||
<ng-template [ngIf]="locale.substr(0, 2) === 'en'"> ™</ng-template>
|
||||
<ng-template [ngIf]="locale.substr(0, 2) === 'en'">®</ng-template>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -95,7 +95,7 @@
|
||||
<div class="col-sm-12">
|
||||
<p *ngIf="officialMempoolSpace">
|
||||
<span>{{ (backendInfo$ | async)?.hostname }} (v{{ (backendInfo$ | async )?.version }}) [<a target="_blank" href="https://github.com/mempool/mempool/commit/{{ (backendInfo$ | async )?.gitCommit | slice:0:8 }}">{{ (backendInfo$ | async )?.gitCommit | slice:0:8 }}</a>]</span>
|
||||
<span *ngIf="stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE"> - (v{{ (servicesBackendInfo$ | async )?.version }}) [{{ (servicesBackendInfo$ | async )?.gitCommit | slice:0:8 }}]</span>
|
||||
<span *ngIf="stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE">[{{ (servicesBackendInfo$ | async )?.gitCommit | slice:0:8 }}]</span>
|
||||
</p>
|
||||
<p *ngIf="!officialMempoolSpace">v{{ packetJsonVersion }} [<a target="_blank" href="https://github.com/mempool/mempool/commit/{{ frontendGitCommitHash }}">{{ frontendGitCommitHash }}</a>]</p>
|
||||
</div>
|
||||
|
||||
@@ -132,10 +132,36 @@ footer .row.version p a {
|
||||
footer .sponsor {
|
||||
height: 31px;
|
||||
align-items: center;
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
max-width: 160px;
|
||||
}
|
||||
|
||||
.explore-tagline-desktop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.explore-tagline-mobile {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 901px) {
|
||||
:host-context(.ltr-layout) .language-selector {
|
||||
float: right !important;
|
||||
}
|
||||
:host-context(.rtl-layout) .language-selector {
|
||||
float: left !important;
|
||||
}
|
||||
|
||||
.explore-tagline-desktop {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.explore-tagline-mobile {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
|
||||
.main-logo {
|
||||
@@ -195,10 +221,6 @@ footer .sponsor {
|
||||
float: none;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
footer .selector:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1147px) {
|
||||
|
||||
@@ -7,6 +7,13 @@ export interface Filter {
|
||||
important?: boolean,
|
||||
}
|
||||
|
||||
export type FilterMode = 'and' | 'or';
|
||||
|
||||
export interface ActiveFilter {
|
||||
mode: FilterMode,
|
||||
filters: string[],
|
||||
}
|
||||
|
||||
// binary flags for transaction classification
|
||||
export const TransactionFlags = {
|
||||
// features
|
||||
@@ -43,6 +50,14 @@ export const TransactionFlags = {
|
||||
sighash_acp: 0b00010000_00000000_00000000_00000000_00000000_00000000n,
|
||||
};
|
||||
|
||||
export function toFlags(filters: string[]): bigint {
|
||||
let flag = 0n;
|
||||
for (const filter of filters) {
|
||||
flag |= TransactionFlags[filter];
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
export const TransactionFilters: { [key: string]: Filter } = {
|
||||
/* features */
|
||||
rbf: { key: 'rbf', label: 'RBF enabled', flag: TransactionFlags.rbf, toggle: 'rbf', important: true },
|
||||
|
||||
@@ -10,8 +10,9 @@ export class RelativeUrlPipe implements PipeTransform {
|
||||
private stateService: StateService,
|
||||
) { }
|
||||
|
||||
transform(value: string): string {
|
||||
let network = this.stateService.network;
|
||||
transform(value: string, swapNetwork?: string): string {
|
||||
let network = swapNetwork || this.stateService.network;
|
||||
if (network === 'mainnet') network = '';
|
||||
if (this.stateService.env.BASE_MODULE === 'liquid' && network === 'liquidtestnet') {
|
||||
network = 'testnet';
|
||||
} else if (this.stateService.env.BASE_MODULE !== 'mempool') {
|
||||
|
||||
347
frontend/src/app/shared/regex.utils.ts
Normal file
347
frontend/src/app/shared/regex.utils.ts
Normal file
@@ -0,0 +1,347 @@
|
||||
import { Env } from '../services/state.service';
|
||||
|
||||
// all base58 characters
|
||||
const BASE58_CHARS = `[a-km-zA-HJ-NP-Z1-9]`;
|
||||
|
||||
// all bech32 characters (after the separator)
|
||||
const BECH32_CHARS_LW = `[ac-hj-np-z02-9]`;
|
||||
const BECH32_CHARS_UP = `[AC-HJ-NP-Z02-9]`;
|
||||
|
||||
// Hex characters
|
||||
const HEX_CHARS = `[a-fA-F0-9]`;
|
||||
|
||||
// A regex to say "A single 0 OR any number with no leading zeroes"
|
||||
// Capped at 9 digits so as to not be confused with lightning channel IDs (which are around 17 digits)
|
||||
// (?: // Start a non-capturing group
|
||||
// 0 // A single 0
|
||||
// | // OR
|
||||
// [1-9][0-9]{0,8} // Any succession of numbers up to 9 digits starting with 1-9
|
||||
// ) // End the non-capturing group.
|
||||
const ZERO_INDEX_NUMBER_CHARS = `(?:0|[1-9][0-9]{0,8})`;
|
||||
|
||||
// Simple digits only regex
|
||||
const NUMBER_CHARS = `[0-9]`;
|
||||
|
||||
// Formatting of the address regex is for readability,
|
||||
// We should ignore formatting it with automated formatting tools like prettier.
|
||||
//
|
||||
// prettier-ignore
|
||||
const ADDRESS_CHARS: {
|
||||
[k in Network]: {
|
||||
base58: string;
|
||||
bech32: string;
|
||||
};
|
||||
} = {
|
||||
mainnet: {
|
||||
base58: `[13]` // Starts with a single 1 or 3
|
||||
+ BASE58_CHARS
|
||||
+ `{26,33}`, // Repeat the previous char 26-33 times.
|
||||
// Version byte 0x00 (P2PKH) can be as short as 27 characters, up to 34 length
|
||||
// P2SH must be 34 length
|
||||
bech32: `(?:`
|
||||
+ `bc1` // Starts with bc1
|
||||
+ BECH32_CHARS_LW
|
||||
+ `{20,100}` // As per bech32, 6 char checksum is minimum
|
||||
+ `|`
|
||||
+ `BC1` // All upper case version
|
||||
+ BECH32_CHARS_UP
|
||||
+ `{20,100}`
|
||||
+ `)`,
|
||||
},
|
||||
testnet: {
|
||||
base58: `[mn2]` // Starts with a single m, n, or 2 (P2PKH is m or n, 2 is P2SH)
|
||||
+ BASE58_CHARS
|
||||
+ `{33,34}`, // m|n is 34 length, 2 is 35 length (We match the first letter separately)
|
||||
bech32: `(?:`
|
||||
+ `tb1` // Starts with tb1
|
||||
+ BECH32_CHARS_LW
|
||||
+ `{20,100}` // As per bech32, 6 char checksum is minimum
|
||||
+ `|`
|
||||
+ `TB1` // All upper case version
|
||||
+ BECH32_CHARS_UP
|
||||
+ `{20,100}`
|
||||
+ `)`,
|
||||
},
|
||||
signet: {
|
||||
base58: `[mn2]`
|
||||
+ BASE58_CHARS
|
||||
+ `{33,34}`,
|
||||
bech32: `(?:`
|
||||
+ `tb1` // Starts with tb1
|
||||
+ BECH32_CHARS_LW
|
||||
+ `{20,100}`
|
||||
+ `|`
|
||||
+ `TB1` // All upper case version
|
||||
+ BECH32_CHARS_UP
|
||||
+ `{20,100}`
|
||||
+ `)`,
|
||||
},
|
||||
liquid: {
|
||||
base58: `[GHPQ]` // PQ is P2PKH, GH is P2SH
|
||||
+ BASE58_CHARS
|
||||
+ `{33}` // All min-max lengths are 34
|
||||
+ `|`
|
||||
+ `[V][TJ]` // Confidential P2PKH or P2SH starts with VT or VJ
|
||||
+ BASE58_CHARS
|
||||
+ `{78}`,
|
||||
bech32: `(?:`
|
||||
+ `(?:` // bech32 liquid starts with ex1 (unconfidential) or lq1 (confidential)
|
||||
+ `ex1`
|
||||
+ `|`
|
||||
+ `lq1`
|
||||
+ `)`
|
||||
+ BECH32_CHARS_LW // blech32 and bech32 are the same alphabet and protocol, different checksums.
|
||||
+ `{20,100}`
|
||||
+ `|`
|
||||
+ `(?:` // Same as above but all upper case
|
||||
+ `EX1`
|
||||
+ `|`
|
||||
+ `LQ1`
|
||||
+ `)`
|
||||
+ BECH32_CHARS_UP
|
||||
+ `{20,100}`
|
||||
+ `)`,
|
||||
},
|
||||
liquidtestnet: {
|
||||
base58: `[89]` // ???(TODO: find version) is P2PKH, 8|9 is P2SH
|
||||
+ BASE58_CHARS
|
||||
+ `{33}`, // P2PKH is ???(TODO: find size), P2SH is 34
|
||||
bech32: `(?:`
|
||||
+ `(?:` // bech32 liquid testnet starts with tex or tlq
|
||||
+ `tex1` // TODO: Why does mempool use this and not ert|el like in the elements source?
|
||||
+ `|`
|
||||
+ `tlq1` // TODO: does this exist?
|
||||
+ `)`
|
||||
+ BECH32_CHARS_LW // blech32 and bech32 are the same alphabet and protocol, different checksums.
|
||||
+ `{20,100}`
|
||||
+ `|`
|
||||
+ `(?:` // Same as above but all upper case
|
||||
+ `TEX1`
|
||||
+ `|`
|
||||
+ `TLQ1`
|
||||
+ `)`
|
||||
+ BECH32_CHARS_UP
|
||||
+ `{20,100}`
|
||||
+ `)`,
|
||||
},
|
||||
bisq: {
|
||||
base58: `(?:[bB][13]` // b or B at the start, followed by a single 1 or 3
|
||||
+ BASE58_CHARS
|
||||
+ `{26,33})`,
|
||||
bech32: `(?:`
|
||||
+ `[bB]bc1` // b or B at the start, followed by bc1
|
||||
+ BECH32_CHARS_LW
|
||||
+ `{20,100}`
|
||||
+ `|`
|
||||
+ `[bB]BC1` // b or B at the start, followed by BC1
|
||||
+ BECH32_CHARS_UP
|
||||
+ `{20,100}`
|
||||
+ `)`,
|
||||
},
|
||||
}
|
||||
type RegexTypeNoAddrNoBlockHash = | `transaction` | `blockheight` | `date` | `timestamp`;
|
||||
export type RegexType = `address` | `blockhash` | RegexTypeNoAddrNoBlockHash;
|
||||
|
||||
export const NETWORKS = [`testnet`, `signet`, `liquid`, `liquidtestnet`, `bisq`, `mainnet`] as const;
|
||||
export type Network = typeof NETWORKS[number]; // Turn const array into union type
|
||||
|
||||
export const ADDRESS_REGEXES: [RegExp, Network][] = NETWORKS
|
||||
.map(network => [getRegex('address', network), network])
|
||||
|
||||
export function findOtherNetworks(address: string, skipNetwork: Network, env: Env): { network: Network, address: string, isNetworkAvailable: boolean }[] {
|
||||
return ADDRESS_REGEXES
|
||||
.filter(([regex, network]) => network !== skipNetwork && regex.test(address))
|
||||
.map(([, network]) => ({ network, address, isNetworkAvailable: isNetworkAvailable(network, env) }));
|
||||
}
|
||||
|
||||
function isNetworkAvailable(network: Network, env: Env): boolean {
|
||||
switch (network) {
|
||||
case 'testnet':
|
||||
return env.TESTNET_ENABLED === true;
|
||||
case 'signet':
|
||||
return env.SIGNET_ENABLED === true;
|
||||
case 'liquid':
|
||||
return env.LIQUID_ENABLED === true;
|
||||
case 'liquidtestnet':
|
||||
return env.LIQUID_TESTNET_ENABLED === true;
|
||||
case 'bisq':
|
||||
return env.BISQ_ENABLED === true;
|
||||
case 'mainnet':
|
||||
return true; // There is no "MAINNET_ENABLED" flag
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function needBaseModuleChange(fromBaseModule: 'mempool' | 'liquid' | 'bisq', toNetwork: Network): boolean {
|
||||
if (!toNetwork) return false; // No target network means no change needed
|
||||
if (fromBaseModule === 'mempool') {
|
||||
return toNetwork !== 'mainnet' && toNetwork !== 'testnet' && toNetwork !== 'signet';
|
||||
}
|
||||
if (fromBaseModule === 'liquid') {
|
||||
return toNetwork !== 'liquid' && toNetwork !== 'liquidtestnet';
|
||||
}
|
||||
if (fromBaseModule === 'bisq') {
|
||||
return toNetwork !== 'bisq';
|
||||
}
|
||||
}
|
||||
|
||||
export function getTargetUrl(toNetwork: Network, address: string, env: Env): string {
|
||||
let targetUrl = '';
|
||||
if (toNetwork === 'liquid' || toNetwork === 'liquidtestnet') {
|
||||
targetUrl = env.LIQUID_WEBSITE_URL;
|
||||
targetUrl += (toNetwork === 'liquidtestnet' ? '/testnet' : '');
|
||||
targetUrl += '/address/';
|
||||
targetUrl += address;
|
||||
}
|
||||
if (toNetwork === 'bisq') {
|
||||
targetUrl = env.BISQ_WEBSITE_URL;
|
||||
targetUrl += '/address/';
|
||||
targetUrl += address;
|
||||
}
|
||||
if (toNetwork === 'mainnet' || toNetwork === 'testnet' || toNetwork === 'signet') {
|
||||
targetUrl = env.MEMPOOL_WEBSITE_URL;
|
||||
targetUrl += (toNetwork === 'mainnet' ? '' : `/${toNetwork}`);
|
||||
targetUrl += '/address/';
|
||||
targetUrl += address;
|
||||
}
|
||||
return targetUrl;
|
||||
}
|
||||
|
||||
export function getRegex(type: RegexTypeNoAddrNoBlockHash): RegExp;
|
||||
export function getRegex(type: 'address', network: Network): RegExp;
|
||||
export function getRegex(type: 'blockhash', network: Network): RegExp;
|
||||
export function getRegex(type: RegexType, network?: Network): RegExp {
|
||||
let regex = `^`; // ^ = Start of string
|
||||
switch (type) {
|
||||
// Match a block height number
|
||||
// [Testing Order]: any order is fine
|
||||
case `blockheight`:
|
||||
regex += ZERO_INDEX_NUMBER_CHARS; // block height is a 0 indexed number
|
||||
break;
|
||||
// Match a 32 byte block hash in hex.
|
||||
// [Testing Order]: Must always be tested before `transaction`
|
||||
case `blockhash`:
|
||||
if (!network) {
|
||||
throw new Error(`Must pass network when type is blockhash`);
|
||||
}
|
||||
let leadingZeroes: number;
|
||||
switch (network) {
|
||||
case `mainnet`:
|
||||
leadingZeroes = 8; // Assumes at least 32 bits of difficulty
|
||||
break;
|
||||
case `testnet`:
|
||||
leadingZeroes = 8; // Assumes at least 32 bits of difficulty
|
||||
break;
|
||||
case `signet`:
|
||||
leadingZeroes = 5;
|
||||
break;
|
||||
case `liquid`:
|
||||
leadingZeroes = 8; // We are not interested in Liquid block hashes
|
||||
break;
|
||||
case `liquidtestnet`:
|
||||
leadingZeroes = 8; // We are not interested in Liquid block hashes
|
||||
break;
|
||||
case `bisq`:
|
||||
leadingZeroes = 8; // Assumes at least 32 bits of difficulty
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid Network ${network} (Unreachable error in TypeScript)`);
|
||||
}
|
||||
regex += `0{${leadingZeroes}}`;
|
||||
regex += `${HEX_CHARS}{${64 - leadingZeroes}}`; // Exactly 64 hex letters/numbers
|
||||
break;
|
||||
// Match a 32 byte tx hash in hex. Contains optional output index specifier.
|
||||
// [Testing Order]: Must always be tested after `blockhash`
|
||||
case `transaction`:
|
||||
regex += `${HEX_CHARS}{64}`; // Exactly 64 hex letters/numbers
|
||||
regex += `(?:`; // Start a non-capturing group
|
||||
regex += `:`; // 1 instances of the symbol ":"
|
||||
regex += ZERO_INDEX_NUMBER_CHARS; // A zero indexed number
|
||||
regex += `)?`; // End the non-capturing group. This group appears 0 or 1 times
|
||||
break;
|
||||
// Match any one of the many address types
|
||||
// [Testing Order]: While possible that a bech32 address happens to be 64 hex
|
||||
// characters in the future (current lengths are not 64), it is highly unlikely
|
||||
// Order therefore, does not matter.
|
||||
case `address`:
|
||||
if (!network) {
|
||||
throw new Error(`Must pass network when type is address`);
|
||||
}
|
||||
regex += `(?:`; // Start a non-capturing group (each network has multiple options)
|
||||
switch (network) {
|
||||
case `mainnet`:
|
||||
regex += ADDRESS_CHARS.mainnet.base58;
|
||||
regex += `|`; // OR
|
||||
regex += ADDRESS_CHARS.mainnet.bech32;
|
||||
regex += `|`; // OR
|
||||
regex += `04${HEX_CHARS}{128}`; // Uncompressed pubkey
|
||||
regex += `|`; // OR
|
||||
regex += `(?:02|03)${HEX_CHARS}{64}`; // Compressed pubkey
|
||||
break;
|
||||
case `testnet`:
|
||||
regex += ADDRESS_CHARS.testnet.base58;
|
||||
regex += `|`; // OR
|
||||
regex += ADDRESS_CHARS.testnet.bech32;
|
||||
regex += `|`; // OR
|
||||
regex += `04${HEX_CHARS}{128}`; // Uncompressed pubkey
|
||||
regex += `|`; // OR
|
||||
regex += `(?:02|03)${HEX_CHARS}{64}`; // Compressed pubkey
|
||||
break;
|
||||
case `signet`:
|
||||
regex += ADDRESS_CHARS.signet.base58;
|
||||
regex += `|`; // OR
|
||||
regex += ADDRESS_CHARS.signet.bech32;
|
||||
regex += `|`; // OR
|
||||
regex += `04${HEX_CHARS}{128}`; // Uncompressed pubkey
|
||||
regex += `|`; // OR
|
||||
regex += `(?:02|03)${HEX_CHARS}{64}`; // Compressed pubkey
|
||||
break;
|
||||
case `liquid`:
|
||||
regex += ADDRESS_CHARS.liquid.base58;
|
||||
regex += `|`; // OR
|
||||
regex += ADDRESS_CHARS.liquid.bech32;
|
||||
break;
|
||||
case `liquidtestnet`:
|
||||
regex += ADDRESS_CHARS.liquidtestnet.base58;
|
||||
regex += `|`; // OR
|
||||
regex += ADDRESS_CHARS.liquidtestnet.bech32;
|
||||
break;
|
||||
case `bisq`:
|
||||
regex += ADDRESS_CHARS.bisq.base58;
|
||||
regex += `|`; // OR
|
||||
regex += ADDRESS_CHARS.bisq.bech32;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid Network ${network} (Unreachable error in TypeScript)`);
|
||||
}
|
||||
regex += `)`; // End the non-capturing group
|
||||
break;
|
||||
// Match a date in the format YYYY-MM-DD (optional: HH:MM)
|
||||
// [Testing Order]: any order is fine
|
||||
case `date`:
|
||||
regex += `(?:`; // Start a non-capturing group
|
||||
regex += `${NUMBER_CHARS}{4}`; // Exactly 4 digits
|
||||
regex += `[-/]`; // 1 instance of the symbol "-" or "/"
|
||||
regex += `${NUMBER_CHARS}{1,2}`; // Exactly 4 digits
|
||||
regex += `[-/]`; // 1 instance of the symbol "-" or "/"
|
||||
regex += `${NUMBER_CHARS}{1,2}`; // Exactly 4 digits
|
||||
regex += `(?:`; // Start a non-capturing group
|
||||
regex += ` `; // 1 instance of the symbol " "
|
||||
regex += `${NUMBER_CHARS}{1,2}`; // Exactly 4 digits
|
||||
regex += `:`; // 1 instance of the symbol ":"
|
||||
regex += `${NUMBER_CHARS}{1,2}`; // Exactly 4 digits
|
||||
regex += `)?`; // End the non-capturing group. This group appears 0 or 1 times
|
||||
regex += `)`; // End the non-capturing group
|
||||
break;
|
||||
// Match a unix timestamp
|
||||
// [Testing Order]: any order is fine
|
||||
case `timestamp`:
|
||||
regex += `${NUMBER_CHARS}{10}`; // Exactly 10 digits
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Invalid RegexType ${type} (Unreachable error in TypeScript)`);
|
||||
}
|
||||
regex += `$`; // $ = End of string
|
||||
return new RegExp(regex);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { NgbCollapseModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstra
|
||||
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
|
||||
import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faHammer, faDatabase, faExchangeAlt, faInfoCircle,
|
||||
faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faClock, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown,
|
||||
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck, faCircleCheck, faUserCircle, faCheck } from '@fortawesome/free-solid-svg-icons';
|
||||
faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl, faDownload, faQrcode, faArrowRightArrowLeft, faArrowsRotate, faCircleLeft, faFastForward, faWallet, faUserClock, faWrench, faUserFriends, faQuestionCircle, faHistory, faSignOutAlt, faKey, faSuitcase, faIdCardAlt, faNetworkWired, faUserCheck, faCircleCheck, faUserCircle, faCheck, faRocket, faScaleBalanced } from '@fortawesome/free-solid-svg-icons';
|
||||
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||
import { MenuComponent } from '../components/menu/menu.component';
|
||||
import { PreviewTitleComponent } from '../components/master-page-preview/preview-title.component';
|
||||
@@ -322,7 +322,7 @@ import { OnlyVsizeDirective, OnlyWeightDirective } from './components/weight-dir
|
||||
ClockFaceComponent,
|
||||
|
||||
OnlyVsizeDirective,
|
||||
OnlyWeightDirective
|
||||
OnlyWeightDirective,
|
||||
]
|
||||
})
|
||||
export class SharedModule {
|
||||
@@ -384,5 +384,7 @@ export class SharedModule {
|
||||
library.addIcons(faCircleCheck);
|
||||
library.addIcons(faUserCircle);
|
||||
library.addIcons(faCheck);
|
||||
library.addIcons(faRocket);
|
||||
library.addIcons(faScaleBalanced);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user