Compare commits
1 Commits
5376-merge
...
natsoni/am
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
865015a193 |
@@ -1,15 +1,10 @@
|
||||
import { Application, Request, Response } from 'express';
|
||||
import config from '../../config';
|
||||
import pricesUpdater from '../../tasks/price-updater';
|
||||
import logger from '../../logger';
|
||||
import PricesRepository from '../../repositories/PricesRepository';
|
||||
|
||||
class PricesRoutes {
|
||||
public initRoutes(app: Application): void {
|
||||
app
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'prices', this.$getCurrentPrices.bind(this))
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'internal/usd-price-history', this.$getAllPrices.bind(this))
|
||||
;
|
||||
app.get(config.MEMPOOL.API_URL_PREFIX + 'prices', this.$getCurrentPrices.bind(this));
|
||||
}
|
||||
|
||||
private $getCurrentPrices(req: Request, res: Response): void {
|
||||
@@ -19,23 +14,6 @@ class PricesRoutes {
|
||||
|
||||
res.json(pricesUpdater.getLatestPrices());
|
||||
}
|
||||
|
||||
private async $getAllPrices(req: Request, res: Response): Promise<void> {
|
||||
res.header('Pragma', 'public');
|
||||
res.header('Cache-control', 'public');
|
||||
res.setHeader('Expires', new Date(Date.now() + 360_0000 / config.MEMPOOL.PRICE_UPDATES_PER_HOUR).toUTCString());
|
||||
|
||||
try {
|
||||
const usdPriceHistory = await PricesRepository.$getPricesTimesAndId();
|
||||
const responseData = usdPriceHistory.map(p => {
|
||||
return { time: p.time, USD: p.USD };
|
||||
});
|
||||
res.status(200).json(responseData);
|
||||
} catch (e: any) {
|
||||
logger.err(`Exception ${e} in PricesRoutes::$getAllPrices. Code: ${e.code}. Message: ${e.message}`);
|
||||
res.status(403).send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new PricesRoutes();
|
||||
|
||||
@@ -19,13 +19,8 @@ interface WalletAddress {
|
||||
lastSync: number;
|
||||
}
|
||||
|
||||
interface WalletConfig {
|
||||
url: string;
|
||||
interface Wallet {
|
||||
name: string;
|
||||
apiKey: string;
|
||||
}
|
||||
|
||||
interface Wallet extends WalletConfig {
|
||||
addresses: Record<string, WalletAddress>;
|
||||
lastPoll: number;
|
||||
}
|
||||
@@ -37,10 +32,10 @@ class WalletApi {
|
||||
private syncing = false;
|
||||
|
||||
constructor() {
|
||||
this.wallets = (config.WALLETS.WALLETS as WalletConfig[]).reduce((acc, wallet) => {
|
||||
acc[wallet.name] = { ...wallet, addresses: {}, lastPoll: 0 };
|
||||
this.wallets = config.WALLETS.ENABLED ? (config.WALLETS.WALLETS as string[]).reduce((acc, wallet) => {
|
||||
acc[wallet] = { name: wallet, addresses: {}, lastPoll: 0 };
|
||||
return acc;
|
||||
}, {} as Record<string, Wallet>);
|
||||
}, {} as Record<string, Wallet>) : {};
|
||||
}
|
||||
|
||||
public getWallet(wallet: string): Record<string, WalletAddress> {
|
||||
@@ -57,18 +52,16 @@ class WalletApi {
|
||||
const wallet = this.wallets[walletKey];
|
||||
if (wallet.lastPoll < (Date.now() - POLL_FREQUENCY)) {
|
||||
try {
|
||||
const response = await axios.get(`${wallet.url}/${wallet.name}`, { headers: { 'Authorization': `${wallet.apiKey}` } });
|
||||
const data: { walletBalances: WalletAddress[] } = response.data;
|
||||
const addresses = data.walletBalances;
|
||||
const newAddresses: Record<string, boolean> = {};
|
||||
const response = await axios.get(config.MEMPOOL_SERVICES.API + `/wallets/${wallet.name}`);
|
||||
const addresses: Record<string, WalletAddress> = response.data;
|
||||
const addressList: WalletAddress[] = Object.values(addresses);
|
||||
// sync all current addresses
|
||||
for (const address of addresses) {
|
||||
for (const address of addressList) {
|
||||
await this.$syncWalletAddress(wallet, address);
|
||||
newAddresses[address.address] = true;
|
||||
}
|
||||
// remove old addresses
|
||||
for (const address of Object.keys(wallet.addresses)) {
|
||||
if (!newAddresses[address]) {
|
||||
if (!addresses[address]) {
|
||||
delete wallet.addresses[address];
|
||||
}
|
||||
}
|
||||
@@ -93,11 +86,10 @@ class WalletApi {
|
||||
const walletAddress: WalletAddress = {
|
||||
address: address.address,
|
||||
active: address.active,
|
||||
transactions: await bitcoinApi.$getAddressTransactionSummary(address.address),
|
||||
transactions: summary,
|
||||
stats: addressInfo.chain_stats,
|
||||
lastSync: Date.now(),
|
||||
};
|
||||
logger.debug(`Synced ${walletAddress.transactions?.length || 0} transactions for wallet ${wallet.name} address ${address.address}`);
|
||||
wallet.addresses[address.address] = walletAddress;
|
||||
} catch (e) {
|
||||
logger.err(`Error syncing wallet address ${address.address}: ${(e instanceof Error ? e.message : e)}`);
|
||||
@@ -150,17 +142,7 @@ class WalletApi {
|
||||
wallet.addresses[address].transactions?.push(txSummary);
|
||||
}
|
||||
if (anyMatch) {
|
||||
for (const address of Object.keys({ ...funded, ...spent })) {
|
||||
if (!walletTransactions[walletKey][address]) {
|
||||
walletTransactions[walletKey][address] = [];
|
||||
}
|
||||
walletTransactions[walletKey][address].push({
|
||||
txid: tx.txid,
|
||||
value: (funded[address] ?? 0) - (spent[address] ?? 0),
|
||||
height: block.height,
|
||||
time: block.timestamp,
|
||||
});
|
||||
}
|
||||
walletTransactions[walletKey].push(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,4 +150,4 @@ class WalletApi {
|
||||
}
|
||||
}
|
||||
|
||||
export default new WalletApi();
|
||||
export default new WalletApi();
|
||||
@@ -164,11 +164,7 @@ interface IConfig {
|
||||
},
|
||||
WALLETS: {
|
||||
ENABLED: boolean;
|
||||
WALLETS: {
|
||||
url: string;
|
||||
name: string;
|
||||
apiKey: string;
|
||||
}[];
|
||||
WALLETS: string[];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div class="acceleration-timeline box" [class.lower-padding]="!tx.status.confirmed">
|
||||
<div class="timeline-wrapper">
|
||||
@if (!tx.status.confirmed || canceled) {
|
||||
@if (!tx.status.confirmed) {
|
||||
<div class="timeline">
|
||||
<div class="intervals">
|
||||
<div class="node-spacer"></div>
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="node-spacer"></div>
|
||||
<div class="interval">
|
||||
<div class="interval-time">
|
||||
@if (eta && !canceled) {
|
||||
@if (eta) {
|
||||
~<app-time [time]="eta?.wait / 1000"></app-time>
|
||||
}
|
||||
</div>
|
||||
@@ -19,20 +19,16 @@
|
||||
<div class="node-spacer"></div>
|
||||
<div class="interval-spacer"></div>
|
||||
<div class="node">
|
||||
<div class="acc-to-confirmed right go-faster" [class.no-animation]="canceled"></div>
|
||||
<div class="acc-to-confirmed right go-faster"></div>
|
||||
</div>
|
||||
<div class="interval-spacer">
|
||||
</div>
|
||||
<div class="node" [id]="'confirmed'">
|
||||
<div class="acc-to-confirmed left go-faster" [class.no-animation]="canceled"></div>
|
||||
<div class="acc-to-confirmed left go-faster"></div>
|
||||
<div class="shape-border waiting">
|
||||
<div class="shape"></div>
|
||||
</div>
|
||||
@if (canceled) {
|
||||
<div class="status"><span class="badge badge-danger" i18n="accelerator.canceled">Canceled</span></div>
|
||||
} @else {
|
||||
<div class="status"><span class="badge badge-waiting" i18n="transaction.rbf.mined">Mined</span></div>
|
||||
}
|
||||
<div class="status"><span class="badge badge-waiting" i18n="transaction.rbf.mined">Mined</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,9 +45,9 @@
|
||||
<div class="interval">
|
||||
<div class="interval-time">
|
||||
@if (tx.status.confirmed) {
|
||||
<app-time [time]="acceleratedToMined"></app-time>
|
||||
} @else if (eta && canceled) {
|
||||
~<app-time [time]="eta?.wait / 1000"></app-time>
|
||||
<div class="interval-time">
|
||||
<app-time [time]="acceleratedToMined"></app-time>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -75,42 +71,42 @@
|
||||
<div class="interval-spacer">
|
||||
<div class="seen-to-acc"></div>
|
||||
</div>
|
||||
<div class="node" [class.accelerated]="!tx.status.confirmed && !canceled" [id]="'accelerated'">
|
||||
<div class="node" [class.accelerated]="!tx.status.confirmed" [id]="'accelerated'">
|
||||
<div class="seen-to-acc left"></div>
|
||||
@if (tx.status.confirmed && !canceled) {
|
||||
@if (tx.status.confirmed) {
|
||||
<div class="acc-to-confirmed right"></div>
|
||||
} @else {
|
||||
<div class="seen-to-acc right"></div>
|
||||
}
|
||||
<div class="shape-border hovering" (pointerover)="onHover($event, 'accelerated');" (pointerout)="onBlur($event);">
|
||||
<div class="shape"></div>
|
||||
@if (!tx.status.confirmed || canceled) {
|
||||
<div class="connector down" [class.loading]="!canceled"></div>
|
||||
@if (!tx.status.confirmed) {
|
||||
<div class="connector down loading"></div>
|
||||
}
|
||||
</div>
|
||||
@if (tx.status.confirmed && !canceled) {
|
||||
@if (tx.status.confirmed) {
|
||||
<div class="status"><span class="badge badge-accelerated" i18n="transaction.audit.accelerated">Accelerated</span></div>
|
||||
}
|
||||
<div class="time" [class.no-margin]="!tx.status.confirmed || canceled" [class.offset-left]="!tx.status.confirmed || canceled">
|
||||
<div class="time" [class.no-margin]="!tx.status.confirmed" [class.offset-left]="!tx.status.confirmed">
|
||||
@if (!tx.status.confirmed) {
|
||||
<span i18n="transaction.audit.accelerated">Accelerated</span>{{ "" }}
|
||||
}
|
||||
@if (useAbsoluteTime) {
|
||||
<span>{{ acceleratedAt * 1000 | date }}</span>
|
||||
} @else {
|
||||
<app-time kind="since" [time]="acceleratedAt" [lowercaseStart]="!tx.status.confirmed || canceled"></app-time>
|
||||
<app-time kind="since" [time]="acceleratedAt" [lowercaseStart]="!tx.status.confirmed"></app-time>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="interval-spacer">
|
||||
@if (tx.status.confirmed && !canceled) {
|
||||
@if (tx.status.confirmed) {
|
||||
<div class="acc-to-confirmed"></div>
|
||||
} @else {
|
||||
<div class="seen-to-acc"></div>
|
||||
}
|
||||
</div>
|
||||
<div class="node" [class.selected]="tx.status.confirmed" [id]="'confirmed'">
|
||||
@if (tx.status.confirmed && !canceled) {
|
||||
@if (tx.status.confirmed) {
|
||||
<div class="acc-to-confirmed left"></div>
|
||||
} @else {
|
||||
<div class="seen-to-acc left"></div>
|
||||
|
||||
@@ -129,9 +129,6 @@
|
||||
margin-left: calc(-4em + 5px);
|
||||
animation: goFasterLeft 0.8s infinite linear;
|
||||
}
|
||||
&.no-animation {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.left {
|
||||
|
||||
@@ -15,7 +15,6 @@ export class AccelerationTimelineComponent implements OnInit, OnChanges {
|
||||
@Input() tx: Transaction;
|
||||
@Input() accelerationInfo: Acceleration;
|
||||
@Input() eta: ETA;
|
||||
@Input() canceled: boolean;
|
||||
|
||||
now: number;
|
||||
accelerateRatio: number;
|
||||
|
||||
@@ -44,7 +44,6 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
@Input() right: number | string = 10;
|
||||
@Input() left: number | string = 70;
|
||||
@Input() widget: boolean = false;
|
||||
@Input() defaultFiat: boolean = false;
|
||||
|
||||
data: any[] = [];
|
||||
fiatData: any[] = [];
|
||||
@@ -85,9 +84,6 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
if (!this.addressSummary$ && (!this.address || !this.stats)) {
|
||||
return;
|
||||
}
|
||||
if (changes.defaultFiat) {
|
||||
this.selected['Fiat'] = !!this.defaultFiat;
|
||||
}
|
||||
if (changes.address || changes.isPubkey || changes.addressSummary$ || changes.stats) {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe();
|
||||
@@ -149,7 +145,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
if (!summary) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const total = this.stats ? (this.stats.funded_txo_sum - this.stats.spent_txo_sum) : summary.reduce((acc, tx) => acc + tx.value, 0);
|
||||
let runningTotal = total;
|
||||
const processData = summary.map(d => {
|
||||
@@ -163,7 +159,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
d
|
||||
};
|
||||
}).reverse();
|
||||
|
||||
|
||||
this.data = processData.filter(({ d }) => d.txid !== undefined).map(({ time, balance, d }) => [time, balance, d]);
|
||||
this.fiatData = processData.map(({ time, fiatBalance, balance, d }) => [time, fiatBalance, d, balance]);
|
||||
|
||||
@@ -181,9 +177,6 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
const maxValue = this.data.reduce((acc, d) => Math.max(acc, Math.abs(d[1] ?? d.value[1])), 0);
|
||||
const minValue = this.data.reduce((acc, d) => Math.min(acc, Math.abs(d[1] ?? d.value[1])), maxValue);
|
||||
|
||||
this.right = this.selected['Fiat'] ? +this.initialRight + 40 : this.initialRight;
|
||||
this.left = this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`] ? this.initialLeft : +this.initialLeft - 40;
|
||||
|
||||
this.chartOptions = {
|
||||
color: [
|
||||
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
@@ -251,7 +244,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
|
||||
const hasTx = data[0].data[2].txid;
|
||||
const date = new Date(data[0].data[0]).toLocaleTimeString(this.locale, { year: 'numeric', month: 'short', day: 'numeric' });
|
||||
|
||||
|
||||
tooltip += `<div>
|
||||
<div style="text-align: right;">
|
||||
<div><b>${date}</b></div>`;
|
||||
@@ -262,10 +255,10 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
: `${data.length} transactions`;
|
||||
tooltip += `<div><b>${header}</b></div>`;
|
||||
}
|
||||
|
||||
|
||||
const formatBTC = (val, decimal) => (val / 100_000_000).toFixed(decimal);
|
||||
const formatFiat = (val) => this.fiatCurrencyPipe.transform(val, null, 'USD');
|
||||
|
||||
|
||||
const btcVal = btcData.reduce((total, d) => total + d.data[2].value, 0);
|
||||
const fiatVal = fiatData.reduce((total, d) => total + d.data[2].value * d.data[2].price / 100_000_000, 0);
|
||||
const btcColor = btcVal === 0 ? '' : (btcVal > 0 ? 'var(--green)' : 'var(--red)');
|
||||
@@ -317,21 +310,21 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
formatter: (val): string => {
|
||||
let valSpan = maxValue - (this.period === 'all' ? 0 : minValue);
|
||||
if (valSpan > 100_000_000_000) {
|
||||
return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 0, undefined, true)} BTC`;
|
||||
return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 0, undefined, true, true)} BTC`;
|
||||
}
|
||||
else if (valSpan > 1_000_000_000) {
|
||||
return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 2, undefined, true)} BTC`;
|
||||
return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 2, undefined, true, true)} BTC`;
|
||||
} else if (valSpan > 100_000_000) {
|
||||
return `${(val / 100_000_000).toFixed(1)} BTC`;
|
||||
} else if (valSpan > 10_000_000) {
|
||||
return `${(val / 100_000_000).toFixed(2)} BTC`;
|
||||
} else if (valSpan > 1_000_000) {
|
||||
if (maxValue > 100_000_000_000) {
|
||||
return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 3, undefined, true)} BTC`;
|
||||
return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 3, undefined, true, true)} BTC`;
|
||||
}
|
||||
return `${(val / 100_000_000).toFixed(3)} BTC`;
|
||||
} else {
|
||||
return `${this.amountShortenerPipe.transform(val, 0, undefined, true)} sats`;
|
||||
return `${this.amountShortenerPipe.transform(val, 0, undefined, true, true)} sats`;
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -345,7 +338,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
axisLabel: {
|
||||
color: 'rgb(110, 112, 121)',
|
||||
formatter: function(val) {
|
||||
return `$${this.amountShortenerPipe.transform(val, 0, undefined, true)}`;
|
||||
return `$${this.amountShortenerPipe.transform(val, 0, undefined, true, true)}`;
|
||||
}.bind(this)
|
||||
},
|
||||
splitLine: {
|
||||
@@ -449,7 +442,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy {
|
||||
right: this.right,
|
||||
}] : undefined
|
||||
};
|
||||
|
||||
|
||||
if (this.chartInstance) {
|
||||
this.chartInstance.setOption(this.chartOptions);
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@
|
||||
<span> </span>
|
||||
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: text-top; font-size: 13px; color: var(--title-fg)"></fa-icon>
|
||||
</a>
|
||||
<app-address-graph [address]="widget.props.address" [addressSummary$]="addressSummary$" [period]="widget.props.period || 'all'" [stats]="address ? address.chain_stats : null" [widget]="true" [defaultFiat]="true" [height]="graphHeight"></app-address-graph>
|
||||
<app-address-graph [address]="widget.props.address" [addressSummary$]="addressSummary$" [period]="widget.props.period || 'all'" [stats]="address ? address.chain_stats : null" [widget]="true" [height]="graphHeight"></app-address-graph>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -315,4 +315,4 @@
|
||||
</ng-template>
|
||||
<ng-template #loadingbig>
|
||||
<span class="skeleton-loader skeleton-loader-big" ></span>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
@@ -247,7 +247,7 @@
|
||||
|
||||
<ng-template #effectiveRateRow>
|
||||
@if (!isLoadingTx) {
|
||||
@if ((cpfpInfo && hasEffectiveFeeRate) || (accelerationInfo && isAcceleration)) {
|
||||
@if ((cpfpInfo && hasEffectiveFeeRate) || accelerationInfo) {
|
||||
<tr>
|
||||
@if (isAcceleration) {
|
||||
<td i18n="transaction.accelerated-fee-rate|Accelerated transaction fee rate">Accelerated fee rate</td>
|
||||
|
||||
@@ -165,12 +165,12 @@
|
||||
<br>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="transactionTime > 0 && tx.acceleratedAt > 0 && (isAcceleration || accelerationCanceled)">
|
||||
<ng-container *ngIf="transactionTime > 0 && tx.acceleratedAt > 0 && isAcceleration">
|
||||
<div class="title float-left">
|
||||
<h2 id="acceleration-timeline" i18n="transaction.acceleration-timeline|Acceleration Timeline">Acceleration Timeline</h2>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<app-acceleration-timeline [transactionTime]="transactionTime" [acceleratedAt]="tx.acceleratedAt" [tx]="tx" [accelerationInfo]="accelerationInfo" [eta]="(ETA$ | async)" [canceled]="accelerationCanceled"></app-acceleration-timeline>
|
||||
<app-acceleration-timeline [transactionTime]="transactionTime" [acceleratedAt]="tx.acceleratedAt" [tx]="tx" [accelerationInfo]="accelerationInfo" [eta]="(ETA$ | async)"></app-acceleration-timeline>
|
||||
<br>
|
||||
</ng-container>
|
||||
|
||||
|
||||
@@ -107,7 +107,6 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
pool: Pool | null;
|
||||
auditStatus: TxAuditStatus | null;
|
||||
isAcceleration: boolean = false;
|
||||
accelerationCanceled: boolean = false;
|
||||
filters: Filter[] = [];
|
||||
showCpfpDetails = false;
|
||||
miningStats: MiningStats;
|
||||
@@ -361,17 +360,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
).subscribe((accelerationHistory) => {
|
||||
for (const acceleration of accelerationHistory) {
|
||||
if (acceleration.txid === this.txId) {
|
||||
if ((acceleration.status === 'completed' || acceleration.status === 'completed_provisional') && acceleration.pools.includes(acceleration.minedByPoolUniqueId)) {
|
||||
const boostCost = acceleration.boostCost || acceleration.bidBoost;
|
||||
acceleration.acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + boostCost) / acceleration.effectiveVsize;
|
||||
acceleration.boost = boostCost;
|
||||
this.tx.acceleratedAt = acceleration.added;
|
||||
this.accelerationInfo = acceleration;
|
||||
}
|
||||
if (acceleration.status === 'failed' || acceleration.status === 'failed_provisional') {
|
||||
this.accelerationCanceled = true;
|
||||
this.tx.acceleratedAt = acceleration.added;
|
||||
this.accelerationInfo = acceleration;
|
||||
if (acceleration.status === 'completed' || acceleration.status === 'completed_provisional') {
|
||||
if (acceleration.pools.includes(acceleration.minedByPoolUniqueId)) {
|
||||
const boostCost = acceleration.boostCost || acceleration.bidBoost;
|
||||
acceleration.acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + boostCost) / acceleration.effectiveVsize;
|
||||
acceleration.boost = boostCost;
|
||||
this.tx.acceleratedAt = acceleration.added;
|
||||
this.accelerationInfo = acceleration;
|
||||
} else {
|
||||
this.tx.feeDelta = undefined;
|
||||
}
|
||||
}
|
||||
this.waitingForAccelerationInfo = false;
|
||||
this.setIsAccelerated();
|
||||
@@ -880,13 +878,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.tx.acceleratedBy = cpfpInfo.acceleratedBy;
|
||||
this.tx.acceleratedAt = cpfpInfo.acceleratedAt;
|
||||
this.tx.feeDelta = cpfpInfo.feeDelta;
|
||||
this.accelerationCanceled = false;
|
||||
this.setIsAccelerated(firstCpfp);
|
||||
} else if (cpfpInfo.acceleratedAt) { // Acceleration was cancelled: reset acceleration state
|
||||
this.tx.acceleratedBy = cpfpInfo.acceleratedBy;
|
||||
this.tx.acceleratedAt = cpfpInfo.acceleratedAt;
|
||||
this.tx.feeDelta = cpfpInfo.feeDelta;
|
||||
this.accelerationCanceled = true;
|
||||
} else if (this.tx.acceleration) { // Acceleration was cancelled while on the tx page, reset acceleration state
|
||||
this.tx.acceleration = false;
|
||||
this.setIsAccelerated(firstCpfp);
|
||||
}
|
||||
|
||||
@@ -910,12 +904,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
setIsAccelerated(initialState: boolean = false) {
|
||||
this.isAcceleration =
|
||||
(
|
||||
(this.tx.acceleration && (!this.tx.status.confirmed || this.waitingForAccelerationInfo)) ||
|
||||
(this.accelerationInfo && this.pool && this.accelerationInfo.pools.some(pool => (pool === this.pool.id)))
|
||||
) &&
|
||||
!this.accelerationCanceled;
|
||||
this.isAcceleration = ((this.tx.acceleration && (!this.tx.status.confirmed || this.waitingForAccelerationInfo)) || (this.accelerationInfo && this.pool && this.accelerationInfo.pools.some(pool => (pool === this.pool.id))));
|
||||
if (this.isAcceleration) {
|
||||
if (initialState) {
|
||||
this.accelerationFlowCompleted = true;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="col-md-12 branding mt-2">
|
||||
<div class="main-logo" [class]="{'services': isServicesPage}">
|
||||
@if (enterpriseInfo?.footer_img) {
|
||||
<img [src]="enterpriseInfo?.footer_img" [alt]="enterpriseInfo.title" height="60px" class="enterprise-logo">
|
||||
<img [src]="enterpriseInfo?.footer_img" [alt]="enterpriseInfo.title" height="60px" class="mr-3">
|
||||
} @else {
|
||||
<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>
|
||||
|
||||
@@ -303,10 +303,6 @@ footer .nowrap {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.enterprise-logo {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
footer .site-options {
|
||||
float: none;
|
||||
margin-top: 15px;
|
||||
|
||||
@@ -5,9 +5,10 @@ import { Pipe, PipeTransform } from '@angular/core';
|
||||
})
|
||||
export class AmountShortenerPipe implements PipeTransform {
|
||||
transform(num: number, ...args: any[]): unknown {
|
||||
const digits = args[0] ?? 1;
|
||||
let digits = args[0] ?? 1;
|
||||
const unit = args[1] || undefined;
|
||||
const isMoney = args[2] || false;
|
||||
const addMoreDigits = args[3] || false;
|
||||
|
||||
if (num < 1000) {
|
||||
return num.toFixed(digits);
|
||||
@@ -25,6 +26,12 @@ export class AmountShortenerPipe implements PipeTransform {
|
||||
const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||
const item = lookup.slice().reverse().find((item) => num >= item.value);
|
||||
|
||||
if (addMoreDigits) {
|
||||
// Add more decimal digits if the integer part is small
|
||||
const integerPartLength = Math.floor(num / item.value).toString().length;
|
||||
digits += Math.max(0, 3 - integerPartLength);
|
||||
}
|
||||
|
||||
if (unit !== undefined) {
|
||||
return item ? (num / item.value).toFixed(digits).replace(rx, '$1') + ' ' + item.symbol + unit : '0';
|
||||
} else {
|
||||
|
||||
@@ -131,8 +131,8 @@ export NVM_DIR="${HOME}/.nvm"
|
||||
source "${NVM_DIR}/nvm.sh"
|
||||
|
||||
# what to look for
|
||||
frontends=(mainnet liquid onbtc bitb meta)
|
||||
backends=(mainnet testnet testnet4 signet liquid liquidtestnet onbtc bitb)
|
||||
frontends=(mainnet liquid onbtc)
|
||||
backends=(mainnet testnet testnet4 signet liquid liquidtestnet onbtc)
|
||||
frontend_repos=()
|
||||
backend_repos=()
|
||||
|
||||
@@ -148,7 +148,7 @@ for repo in $backends;do
|
||||
done
|
||||
|
||||
# update all repos
|
||||
for repo in $frontend_repos $backend_repos;do
|
||||
for repo in $backend_repos;do
|
||||
update_repo "${repo}"
|
||||
done
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"OFFICIAL_MEMPOOL_SPACE": true,
|
||||
"TESTNET_ENABLED": true,
|
||||
"TESTNET4_ENABLED": true,
|
||||
"LIQUID_ENABLED": true,
|
||||
"LIQUID_TESTNET_ENABLED": true,
|
||||
"BISQ_ENABLED": true,
|
||||
"BISQ_SEPARATE_BACKEND": true,
|
||||
"SIGNET_ENABLED": true,
|
||||
"MEMPOOL_WEBSITE_URL": "https://mempool.space",
|
||||
"LIQUID_WEBSITE_URL": "https://liquid.network",
|
||||
"BISQ_WEBSITE_URL": "https://bisq.markets",
|
||||
"ITEMS_PER_PAGE": 25,
|
||||
"LIGHTNING": true,
|
||||
"ACCELERATOR": true,
|
||||
"PUBLIC_ACCELERATIONS": true,
|
||||
"AUDIT": true,
|
||||
"CUSTOMIZATION": "custom-meta-config.json"
|
||||
}
|
||||
@@ -15,7 +15,7 @@ screen -dmS x startx
|
||||
sleep 3
|
||||
|
||||
# start unfurlers for each frontend
|
||||
for site in mainnet liquid onbtc bitb meta;do
|
||||
for site in mainnet liquid onbtc;do
|
||||
cd "$HOME/${site}/unfurler" && \
|
||||
echo "starting mempool unfurler: ${site}" && \
|
||||
screen -dmS "unfurler-${site}" sh -c 'while true;do npm run unfurler;sleep 2;done'
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"SERVER": {
|
||||
"HOST": "https://metaplanet.mempool.space",
|
||||
"HTTP_PORT": 8005
|
||||
},
|
||||
"MEMPOOL": {
|
||||
"HTTP_HOST": "http://127.0.0.1",
|
||||
"HTTP_PORT": 85,
|
||||
"NETWORK": "meta"
|
||||
},
|
||||
"PUPPETEER": {
|
||||
"CLUSTER_SIZE": 8,
|
||||
"EXEC_PATH": "/usr/local/bin/chrome",
|
||||
"MAX_PAGE_AGE": 86400,
|
||||
"RENDER_TIMEOUT": 3000
|
||||
}
|
||||
}
|
||||
@@ -281,46 +281,6 @@ export const networks = {
|
||||
routes: routes.lightning.routes,
|
||||
}
|
||||
}
|
||||
},
|
||||
bitb: {
|
||||
title: 'BITB | Bitwise Bitcoin ETF',
|
||||
description: 'BITB provides low-cost access to bitcoin through a professionally managed fund',
|
||||
fallbackImg: '/resources/bitb/bitb-preview.jpg',
|
||||
routes: { // only dynamic routes supported
|
||||
block: routes.block,
|
||||
address: routes.address,
|
||||
tx: routes.tx,
|
||||
mining: {
|
||||
title: "Mining",
|
||||
routes: {
|
||||
pool: routes.mining.routes.pool,
|
||||
}
|
||||
},
|
||||
lightning: {
|
||||
title: "Lightning",
|
||||
routes: routes.lightning.routes,
|
||||
}
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
title: 'Metaplanet Inc.',
|
||||
description: 'Secure the Future with Bitcoin',
|
||||
fallbackImg: '/resources/meta/meta-preview.png',
|
||||
routes: { // only dynamic routes supported
|
||||
block: routes.block,
|
||||
address: routes.address,
|
||||
tx: routes.tx,
|
||||
mining: {
|
||||
title: "Mining",
|
||||
routes: {
|
||||
pool: routes.mining.routes.pool,
|
||||
}
|
||||
},
|
||||
lightning: {
|
||||
title: "Lightning",
|
||||
routes: routes.lightning.routes,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user