diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index ee9df9151..6cb361ffd 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository'; import { RowDataPacket } from 'mysql2'; class DatabaseMigration { - private static currentVersion = 83; + private static currentVersion = 93; private queryTimeout = 3600_000; private statisticsAddedIndexed = false; private uniqueLogs: string[] = []; @@ -710,6 +710,97 @@ class DatabaseMigration { await this.$executeQuery('ALTER TABLE `blocks` ADD first_seen datetime(6) DEFAULT NULL'); await this.updateToSchemaVersion(83); } + + // add new pools indexes + if (databaseSchemaVersion < 84 && isBitcoin === true) { + await this.$executeQuery(` + ALTER TABLE \`pools\` + ADD INDEX \`slug\` (\`slug\`), + ADD INDEX \`unique_id\` (\`unique_id\`) + `); + await this.updateToSchemaVersion(84); + } + + // lightning channels indexes + if (databaseSchemaVersion < 85 && isBitcoin === true) { + await this.$executeQuery(` + ALTER TABLE \`channels\` + ADD INDEX \`created\` (\`created\`), + ADD INDEX \`capacity\` (\`capacity\`), + ADD INDEX \`closing_reason\` (\`closing_reason\`), + ADD INDEX \`closing_resolved\` (\`closing_resolved\`) + `); + await this.updateToSchemaVersion(85); + } + + // lightning nodes indexes + if (databaseSchemaVersion < 86 && isBitcoin === true) { + await this.$executeQuery(` + ALTER TABLE \`nodes\` + ADD INDEX \`status\` (\`status\`), + ADD INDEX \`channels\` (\`channels\`), + ADD INDEX \`country_id\` (\`country_id\`), + ADD INDEX \`as_number\` (\`as_number\`), + ADD INDEX \`first_seen\` (\`first_seen\`) + `); + await this.updateToSchemaVersion(86); + } + + // lightning node sockets indexes + if (databaseSchemaVersion < 87 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `nodes_sockets` ADD INDEX `type` (`type`)'); + await this.updateToSchemaVersion(87); + } + + // lightning stats indexes + if (databaseSchemaVersion < 88 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD INDEX `added` (`added`)'); + await this.updateToSchemaVersion(88); + } + + // geo names indexes + if (databaseSchemaVersion < 89 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `geo_names` ADD INDEX `names` (`names`)'); + await this.updateToSchemaVersion(89); + } + + // hashrates indexes + if (databaseSchemaVersion < 90 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `hashrates` ADD INDEX `type` (`type`)'); + await this.updateToSchemaVersion(90); + } + + // block audits indexes + if (databaseSchemaVersion < 91 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD INDEX `time` (`time`)'); + await this.updateToSchemaVersion(91); + } + + // elements_pegs indexes + if (databaseSchemaVersion < 92 && config.MEMPOOL.NETWORK === 'liquid') { + await this.$executeQuery(` + ALTER TABLE \`elements_pegs\` + ADD INDEX \`block\` (\`block\`), + ADD INDEX \`datetime\` (\`datetime\`), + ADD INDEX \`amount\` (\`amount\`), + ADD INDEX \`bitcoinaddress\` (\`bitcoinaddress\`), + ADD INDEX \`bitcointxid\` (\`bitcointxid\`) + `); + await this.updateToSchemaVersion(92); + } + + // federation_txos indexes + if (databaseSchemaVersion < 93 && config.MEMPOOL.NETWORK === 'liquid') { + await this.$executeQuery(` + ALTER TABLE \`federation_txos\` + ADD INDEX \`unspent\` (\`unspent\`), + ADD INDEX \`lastblockupdate\` (\`lastblockupdate\`), + ADD INDEX \`blocktime\` (\`blocktime\`), + ADD INDEX \`emergencyKey\` (\`emergencyKey\`), + ADD INDEX \`expiredAt\` (\`expiredAt\`) + `); + await this.updateToSchemaVersion(93); + } } /** diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index 6e547e653..ba4ce2ed0 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -382,7 +382,7 @@ class MempoolBlocks { const ancestors: Ancestor[] = []; const descendants: Ancestor[] = []; - let ancestor: MempoolTransactionExtended + let ancestor: MempoolTransactionExtended; for (const cluster of clusters) { for (const memberTxid of cluster) { const mempoolTx = mempool[memberTxid]; @@ -462,7 +462,7 @@ class MempoolBlocks { for (let i = 0; i < block.length; i++) { const txid = block[i]; - if (txid) { + if (txid in mempool) { mempoolTx = mempool[txid]; // save position in projected blocks mempoolTx.position = { @@ -481,6 +481,9 @@ class MempoolBlocks { mempoolTx.acceleratedAt = acceleration?.added; mempoolTx.feeDelta = acceleration?.feeDelta; for (const ancestor of mempoolTx.ancestors || []) { + if (!(ancestor.txid in mempool)) { + continue; + } if (!mempool[ancestor.txid].acceleration) { mempool[ancestor.txid].cpfpDirty = true; } @@ -688,7 +691,7 @@ class MempoolBlocks { [pool: string]: { name: string, block: number, vsize: number, accelerations: string[], complete: boolean }; } = {}; // prepare a list of accelerations in ascending order (we'll pop items off the end of the list) - const accQueue: { acceleration: Acceleration, rate: number, vsize: number }[] = Object.values(accelerations).map(acc => { + const accQueue: { acceleration: Acceleration, rate: number, vsize: number }[] = Object.values(accelerations).filter(acc => acc.txid in mempoolCache).map(acc => { let vsize = mempoolCache[acc.txid].vsize; for (const ancestor of mempoolCache[acc.txid].ancestors || []) { vsize += (ancestor.weight / 4); diff --git a/backend/src/api/services/acceleration.ts b/backend/src/api/services/acceleration.ts index e18bcf464..053da6e82 100644 --- a/backend/src/api/services/acceleration.ts +++ b/backend/src/api/services/acceleration.ts @@ -246,17 +246,22 @@ class AccelerationApi { this.startedWebsocketLoop = true; if (!this.ws) { this.ws = new WebSocket(this.websocketPath); - this.websocketConnected = true; + this.lastPing = 0; this.ws.on('open', () => { logger.info(`Acceleration websocket opened to ${this.websocketPath}`); + this.websocketConnected = true; this.ws?.send(JSON.stringify({ 'watch-accelerations': true })); }); this.ws.on('error', (error) => { - logger.err(`Acceleration websocket error on ${this.websocketPath}: ` + error); + let errMsg = `Acceleration websocket error on ${this.websocketPath}: ${error['code']}`; + if (error['errors']) { + errMsg += ' - ' + error['errors'].join(' - '); + } + logger.err(errMsg); this.ws = null; this.websocketConnected = false; }); @@ -285,16 +290,28 @@ class AccelerationApi { logger.debug('received pong from acceleration websocket server'); this.lastPong = Date.now(); }); - } else { - if (this.lastPing > this.lastPong && Date.now() - this.lastPing > 10000) { + } else if (this.websocketConnected) { + if (this.lastPing && this.lastPing > this.lastPong && (Date.now() - this.lastPing > 10000)) { logger.warn('No pong received within 10 seconds, terminating connection'); - this.ws.terminate(); - this.ws = null; - this.websocketConnected = false; - } else if (Date.now() - this.lastPing > 30000) { + try { + this.ws?.terminate(); + } catch (e) { + logger.warn('failed to terminate acceleration websocket connection: ' + (e instanceof Error ? e.message : e)); + } finally { + this.ws = null; + this.websocketConnected = false; + this.lastPing = 0; + } + } else if (!this.lastPing || (Date.now() - this.lastPing > 30000)) { logger.debug('sending ping to acceleration websocket server'); - this.ws.ping(); - this.lastPing = Date.now(); + if (this.ws?.readyState === WebSocket.OPEN) { + try { + this.ws?.ping(); + this.lastPing = Date.now(); + } catch (e) { + logger.warn('failed to send ping to acceleration websocket server: ' + (e instanceof Error ? e.message : e)); + } + } } } await new Promise(resolve => setTimeout(resolve, 5000)); diff --git a/frontend/custom-meta-config.json b/frontend/custom-meta-config.json new file mode 100644 index 000000000..6fa46192a --- /dev/null +++ b/frontend/custom-meta-config.json @@ -0,0 +1,51 @@ +{ + "theme": "contrast", + "enterprise": "meta", + "branding": { + "name": "metaplanet", + "title": "Metaplanet", + "site_id": 21, + "header_img": "/resources/metalogo.svg", + "footer_img": "/resources/metalogo.svg" + }, + "dashboard": { + "widgets": [ + { + "component": "fees", + "mobileOrder": 4 + }, + { + "component": "walletBalance", + "mobileOrder": 1, + "props": { + "wallet": "3350" + } + }, + { + "component": "twitter", + "mobileOrder": 5, + "props": { + "handle": "Metaplanet_JP" + } + }, + { + "component": "wallet", + "mobileOrder": 2, + "props": { + "wallet": "3350", + "period": "all" + } + }, + { + "component": "blocks" + }, + { + "component": "walletTransactions", + "mobileOrder": 3, + "props": { + "wallet": "3350" + } + } + ] + } +} \ No newline at end of file diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts index 425e00d9e..1a5ace34f 100644 --- a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef, SimpleChanges, HostListener } from '@angular/core'; import { Subscription, tap, of, catchError, Observable, switchMap } from 'rxjs'; import { ServicesApiServices } from '@app/services/services-api.service'; -import { md5, insecureRandomUUID } from '@app/shared/common.utils'; +import { md5 } from '@app/shared/common.utils'; import { StateService } from '@app/services/state.service'; import { AudioService } from '@app/services/audio.service'; import { ETA, EtaService } from '@app/services/eta.service'; @@ -94,7 +94,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { auth: IAuth | null = null; // accelerator stuff - accelerationUUID: string; accelerationSubscription: Subscription; difficultySubscription: Subscription; estimateSubscription: Subscription; @@ -138,7 +137,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { private enterpriseService: EnterpriseService, ) { this.isProdDomain = this.stateService.env.PROD_DOMAINS.indexOf(document.location.hostname) > -1; - this.accelerationUUID = insecureRandomUUID(); // Check if Apple Pay available // https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/checking_for_apple_pay_availability#overview @@ -388,7 +386,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { this.accelerationSubscription = this.servicesApiService.accelerate$( this.tx.txid, this.userBid, - this.accelerationUUID ).subscribe({ next: () => { this.processing = false; @@ -522,7 +519,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { tokenResult.token, cardTag, `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, - this.accelerationUUID, costUSD ).subscribe({ next: () => { @@ -622,7 +618,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { tokenResult.token, cardTag, `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, - this.accelerationUUID, costUSD ).subscribe({ next: () => { @@ -713,7 +708,6 @@ export class AccelerateCheckout implements OnInit, OnDestroy { tokenResult.token, tokenResult.details.cashAppPay.cashtag, tokenResult.details.cashAppPay.referenceId, - this.accelerationUUID, costUSD ).subscribe({ next: () => { diff --git a/frontend/src/app/components/address-graph/address-graph.component.ts b/frontend/src/app/components/address-graph/address-graph.component.ts index e8762fbec..e4c38c897 100644 --- a/frontend/src/app/components/address-graph/address-graph.component.ts +++ b/frontend/src/app/components/address-graph/address-graph.component.ts @@ -10,7 +10,6 @@ import { RelativeUrlPipe } from '@app/shared/pipes/relative-url/relative-url.pip import { StateService } from '@app/services/state.service'; import { PriceService } from '@app/services/price.service'; import { FiatCurrencyPipe } from '@app/shared/pipes/fiat-currency.pipe'; -import { FiatShortenerPipe } from '@app/shared/pipes/fiat-shortener.pipe'; const periodSeconds = { '1d': (60 * 60 * 24), @@ -77,7 +76,6 @@ export class AddressGraphComponent implements OnChanges, OnDestroy { private relativeUrlPipe: RelativeUrlPipe, private priceService: PriceService, private fiatCurrencyPipe: FiatCurrencyPipe, - private fiatShortenerPipe: FiatShortenerPipe, private zone: NgZone, ) {} @@ -245,18 +243,19 @@ export class AddressGraphComponent implements OnChanges, OnDestroy { let tooltip = '
'; 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 += `
+
+
${date}
`; + if (hasTx) { const header = data.length === 1 ? `${data[0].data[2].txid.slice(0, 6)}...${data[0].data[2].txid.slice(-6)}` : `${data.length} transactions`; - tooltip += `${header}`; + tooltip += `
${header}
`; } - const date = new Date(data[0].data[0]).toLocaleTimeString(this.locale, { year: 'numeric', month: 'short', day: 'numeric' }); - - tooltip += `
-
`; - const formatBTC = (val, decimal) => (val / 100_000_000).toFixed(decimal); const formatFiat = (val) => this.fiatCurrencyPipe.transform(val, null, 'USD'); @@ -291,7 +290,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy { } } - tooltip += `
${date}
`; + tooltip += `
`; return tooltip; }.bind(this) }, @@ -311,18 +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)} BTC`; + return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 0, undefined, true)} BTC`; } else if (valSpan > 1_000_000_000) { - return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 2)} BTC`; + return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 2, undefined, 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 `${(val / 100_000_000).toFixed(3)} BTC`; } else { - return `${this.amountShortenerPipe.transform(val, 0)} sats`; + return `${this.amountShortenerPipe.transform(val, 0, undefined, true)} sats`; } } }, @@ -336,7 +338,7 @@ export class AddressGraphComponent implements OnChanges, OnDestroy { axisLabel: { color: 'rgb(110, 112, 121)', formatter: function(val) { - return this.fiatShortenerPipe.transform(val, null, 'USD'); + return `$${this.amountShortenerPipe.transform(val, 0, undefined, true)}`; }.bind(this) }, splitLine: { diff --git a/frontend/src/app/components/clipboard/clipboard.component.html b/frontend/src/app/components/clipboard/clipboard.component.html index d23ccdf8c..c3a18d90b 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.html +++ b/frontend/src/app/components/clipboard/clipboard.component.html @@ -1,15 +1,17 @@ - - - + {{ copiedMessage }} diff --git a/frontend/src/app/components/clipboard/clipboard.component.scss b/frontend/src/app/components/clipboard/clipboard.component.scss index 49294e548..6ae620ae7 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.scss +++ b/frontend/src/app/components/clipboard/clipboard.component.scss @@ -7,7 +7,19 @@ padding-left: 0.4rem; } -img { - position: relative; - left: -3px; -} \ No newline at end of file +.copied-message { + background: color-mix(in srgb, var(--active-bg) 95%, transparent); + color: var(--fg); + font-family: sans-serif; + font-size: .8rem; + font-weight: 400; + text-decoration: none; + text-align: left; + padding: .6em .75rem; + border-radius: 4px; + position: absolute; + white-space: nowrap; + box-shadow: 0 .5rem 1rem -.5rem #000; + z-index: 1000; + opacity: .9; +} diff --git a/frontend/src/app/components/clipboard/clipboard.component.ts b/frontend/src/app/components/clipboard/clipboard.component.ts index 6e577d8b3..31f882d12 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.ts +++ b/frontend/src/app/components/clipboard/clipboard.component.ts @@ -1,6 +1,4 @@ -import { Component, ViewChild, ElementRef, AfterViewInit, Input, ChangeDetectionStrategy } from '@angular/core'; -import * as ClipboardJS from 'clipboard'; -import * as tlite from 'tlite'; +import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; @Component({ selector: 'app-clipboard', @@ -8,15 +6,14 @@ import * as tlite from 'tlite'; styleUrls: ['./clipboard.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ClipboardComponent implements AfterViewInit { - @ViewChild('btn') btn: ElementRef; - @ViewChild('buttonWrapper') buttonWrapper: ElementRef; +export class ClipboardComponent { @Input() button = false; @Input() class = 'btn btn-secondary ml-1'; @Input() size: 'small' | 'normal' | 'large' = 'normal'; @Input() text: string; @Input() leftPadding = true; copiedMessage: string = $localize`:@@clipboard.copied-message:Copied!`; + showMessage = false; widths = { small: '10', @@ -24,22 +21,40 @@ export class ClipboardComponent implements AfterViewInit { large: '18', }; - clipboard: any; + constructor( + private cd: ChangeDetectorRef, + ) { } - constructor() { } - - ngAfterViewInit() { - this.clipboard = new ClipboardJS(this.btn.nativeElement); - this.clipboard.on('success', () => { - tlite.show(this.buttonWrapper.nativeElement); - setTimeout(() => { - tlite.hide(this.buttonWrapper.nativeElement); - }, 1000); - }); + async copyText() { + if (this.text && !this.showMessage) { + try { + await this.copyToClipboard(this.text); + this.showMessage = true; + this.cd.markForCheck(); + setTimeout(() => { + this.showMessage = false; + this.cd.markForCheck(); + }, 1000); + } catch (error) { + console.error('Clipboard copy failed:', error); + } + } } - onDestroy() { - this.clipboard.destroy(); + async copyToClipboard(text: string) { + if (navigator.clipboard) { + await navigator.clipboard.writeText(text); + } else { + // Use the 'out of viewport hidden text area' trick on non-secure contexts + const textarea = document.createElement('textarea'); + textarea.value = this.text; + textarea.style.opacity = '0'; + textarea.setAttribute('readonly', 'true'); // Don't trigger keyboard on mobile + document.body.appendChild(textarea); + textarea.select(); + document.execCommand('copy'); + textarea.remove(); + } } } diff --git a/frontend/src/app/components/transaction/transaction-details/transaction-details.component.html b/frontend/src/app/components/transaction/transaction-details/transaction-details.component.html index acadc8818..9bdf4066a 100644 --- a/frontend/src/app/components/transaction/transaction-details/transaction-details.component.html +++ b/frontend/src/app/components/transaction/transaction-details/transaction-details.component.html @@ -217,10 +217,10 @@ Fee {{ tx.fee | number }} sats - @if (accelerationInfo?.bidBoost ?? tx.feeDelta > 0) { + @if (isAcceleration && accelerationInfo?.bidBoost ?? tx.feeDelta > 0) { +{{ accelerationInfo?.bidBoost ?? tx.feeDelta | number }} sats } - + } @else { diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index f19a5bcbd..a1b48766a 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -879,6 +879,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.tx.acceleratedAt = cpfpInfo.acceleratedAt; this.tx.feeDelta = cpfpInfo.feeDelta; this.setIsAccelerated(firstCpfp); + } else if (this.tx.acceleration) { // Acceleration was cancelled while on the tx page, reset acceleration state + this.tx.acceleration = false; + this.setIsAccelerated(firstCpfp); } if (this.notAcceleratedOnLoad === null) { diff --git a/frontend/src/app/docs/api-docs/api-docs-data.ts b/frontend/src/app/docs/api-docs/api-docs-data.ts index cad4b47bf..1f83cabc9 100644 --- a/frontend/src/app/docs/api-docs/api-docs-data.ts +++ b/frontend/src/app/docs/api-docs/api-docs-data.ts @@ -9339,7 +9339,7 @@ export const restApiDocsData = [ fragment: "accelerator-history", title: "GET Acceleration History", description: { - default: "

Returns the user's past acceleration requests.

Pass one of the following for :status: all, requested, accelerating, mined, completed, failed. Pass true in :details to get a detailed history of the acceleration request.

" + default: "

Returns the user's past acceleration requests.

Pass one of the following for :status (required): all, requested, accelerating, mined, completed, failed.
Pass true in :details to get a detailed history of the acceleration request.

" }, urlString: "/v1/services/accelerator/history?status=:status&details=:details", showConditions: [""], @@ -9449,6 +9449,36 @@ export const restApiDocsData = [ } } }, + { + options: { officialOnly: true }, + type: "endpoint", + category: "accelerator-private", + httpRequestMethod: "POST", + fragment: "accelerator-cancel", + title: "POST Cancel Acceleration (Pro)", + description: { + default: "

Sends a request to cancel an acceleration in the accelerating status.
You can retreive eligible acceleration id using the history endpoint GET /api/v1/services/accelerator/history?status=accelerating." + }, + urlString: "/v1/services/accelerator/cancel", + showConditions: [""], + showJsExamples: showJsExamplesDefaultFalse, + codeExample: { + default: { + codeTemplate: { + curl: `%{1}" "[[hostname]][[baseNetworkUrl]]/api/v1/services/accelerator/cancel`, //custom interpolation technique handled in replaceCurlPlaceholder() + commonJS: ``, + esModule: `` + }, + codeSampleMainnet: { + esModule: [], + commonJS: [], + curl: ["id=42"], + headers: "X-Mempool-Auth: stacksats", + response: `HTTP/1.1 200 OK`, + }, + } + } + }, ]; export const faqData = [ diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts index 2b0f884ff..2ecfe06ff 100644 --- a/frontend/src/app/services/services-api.service.ts +++ b/frontend/src/app/services/services-api.service.ts @@ -131,20 +131,20 @@ export class ServicesApiServices { return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/estimate`, { txInput: txInput }, { observe: 'response' }); } - accelerate$(txInput: string, userBid: number, accelerationUUID: string) { - return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate`, { txInput: txInput, userBid: userBid, accelerationUUID: accelerationUUID }); + accelerate$(txInput: string, userBid: number) { + return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate`, { txInput: txInput, userBid: userBid}); } - accelerateWithCashApp$(txInput: string, token: string, cashtag: string, referenceId: string, accelerationUUID: string, userApprovedUSD: number) { - return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/cashapp`, { txInput: txInput, token: token, cashtag: cashtag, referenceId: referenceId, accelerationUUID: accelerationUUID, userApprovedUSD: userApprovedUSD }); + accelerateWithCashApp$(txInput: string, token: string, cashtag: string, referenceId: string, userApprovedUSD: number) { + return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/cashapp`, { txInput: txInput, token: token, cashtag: cashtag, referenceId: referenceId, userApprovedUSD: userApprovedUSD }); } - accelerateWithApplePay$(txInput: string, token: string, cardTag: string, referenceId: string, accelerationUUID: string, userApprovedUSD: number) { - return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/applePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, accelerationUUID: accelerationUUID, userApprovedUSD: userApprovedUSD }); + accelerateWithApplePay$(txInput: string, token: string, cardTag: string, referenceId: string, userApprovedUSD: number) { + return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/applePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, userApprovedUSD: userApprovedUSD }); } - accelerateWithGooglePay$(txInput: string, token: string, cardTag: string, referenceId: string, accelerationUUID: string, userApprovedUSD: number) { - return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/googlePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, accelerationUUID: accelerationUUID, userApprovedUSD: userApprovedUSD }); + accelerateWithGooglePay$(txInput: string, token: string, cardTag: string, referenceId: string, userApprovedUSD: number) { + return this.httpClient.post(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/googlePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, userApprovedUSD: userApprovedUSD }); } getAccelerations$(): Observable { diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 5ec13c03f..0f5368244 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -37,6 +37,7 @@ export class WebsocketService { private isTrackingWallet: boolean = false; private trackingWalletName: string; private trackingMempoolBlock: number; + private trackingMempoolBlockNetwork: string; private stoppingTrackMempoolBlock: any | null = null; private latestGitCommit = ''; private onlineCheckTimeout: number; @@ -226,10 +227,11 @@ export class WebsocketService { clearTimeout(this.stoppingTrackMempoolBlock); } // skip duplicate tracking requests - if (force || this.trackingMempoolBlock !== block) { + if (force || this.trackingMempoolBlock !== block || this.network !== this.trackingMempoolBlockNetwork) { this.websocketSubject.next({ 'track-mempool-block': block }); this.isTrackingMempoolBlock = true; this.trackingMempoolBlock = block; + this.trackingMempoolBlockNetwork = this.network; return true; } return false; diff --git a/frontend/src/app/shared/common.utils.ts b/frontend/src/app/shared/common.utils.ts index f329b55e4..9b53600c1 100644 --- a/frontend/src/app/shared/common.utils.ts +++ b/frontend/src/app/shared/common.utils.ts @@ -214,19 +214,6 @@ export function renderSats(value: number, network: string, mode: 'sats' | 'btc' } } -export function insecureRandomUUID(): string { - const hexDigits = '0123456789abcdef'; - const uuidLengths = [8, 4, 4, 4, 12]; - let uuid = ''; - for (const length of uuidLengths) { - for (let i = 0; i < length; i++) { - uuid += hexDigits[Math.floor(Math.random() * 16)]; - } - uuid += '-'; - } - return uuid.slice(0, -1); -} - export function sleep$(ms: number): Promise { return new Promise((resolve) => { setTimeout(() => { diff --git a/frontend/src/index.mempool.meta.html b/frontend/src/index.mempool.meta.html new file mode 100644 index 000000000..92154f8db --- /dev/null +++ b/frontend/src/index.mempool.meta.html @@ -0,0 +1,45 @@ + + + + + + Metaplanet Inc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/resources/meta/favicons/android-chrome-192x192.png b/frontend/src/resources/meta/favicons/android-chrome-192x192.png new file mode 100644 index 000000000..448d5ce91 Binary files /dev/null and b/frontend/src/resources/meta/favicons/android-chrome-192x192.png differ diff --git a/frontend/src/resources/meta/favicons/android-chrome-512x512.png b/frontend/src/resources/meta/favicons/android-chrome-512x512.png new file mode 100644 index 000000000..5164c7746 Binary files /dev/null and b/frontend/src/resources/meta/favicons/android-chrome-512x512.png differ diff --git a/frontend/src/resources/meta/favicons/apple-touch-icon.png b/frontend/src/resources/meta/favicons/apple-touch-icon.png new file mode 100644 index 000000000..bd5b04f4b Binary files /dev/null and b/frontend/src/resources/meta/favicons/apple-touch-icon.png differ diff --git a/frontend/src/resources/meta/favicons/favicon-16x16.png b/frontend/src/resources/meta/favicons/favicon-16x16.png new file mode 100644 index 000000000..2c9716325 Binary files /dev/null and b/frontend/src/resources/meta/favicons/favicon-16x16.png differ diff --git a/frontend/src/resources/meta/favicons/favicon-32x32.png b/frontend/src/resources/meta/favicons/favicon-32x32.png new file mode 100644 index 000000000..6fb88e678 Binary files /dev/null and b/frontend/src/resources/meta/favicons/favicon-32x32.png differ diff --git a/frontend/src/resources/meta/favicons/favicon.ico b/frontend/src/resources/meta/favicons/favicon.ico new file mode 100644 index 000000000..bd25b818f Binary files /dev/null and b/frontend/src/resources/meta/favicons/favicon.ico differ diff --git a/frontend/src/resources/meta/favicons/site.webmanifest b/frontend/src/resources/meta/favicons/site.webmanifest new file mode 100644 index 000000000..45dc8a206 --- /dev/null +++ b/frontend/src/resources/meta/favicons/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/frontend/src/resources/meta/meta-preview.png b/frontend/src/resources/meta/meta-preview.png new file mode 100644 index 000000000..d569aae0e Binary files /dev/null and b/frontend/src/resources/meta/meta-preview.png differ diff --git a/frontend/src/resources/metalogo.svg b/frontend/src/resources/metalogo.svg new file mode 100644 index 000000000..e3174dc62 --- /dev/null +++ b/frontend/src/resources/metalogo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/production/bitcoin.conf b/production/bitcoin.conf index 63baa32b5..57d993eb4 100644 --- a/production/bitcoin.conf +++ b/production/bitcoin.conf @@ -4,7 +4,6 @@ txindex=1 coinstatsindex=1 listen=1 discover=1 -par=16 dbcache=8192 mempoolfullrbf=1 maxconnections=100 diff --git a/production/mempool-config.mainnet.json b/production/mempool-config.mainnet.json index f57978043..39d82d8d1 100644 --- a/production/mempool-config.mainnet.json +++ b/production/mempool-config.mainnet.json @@ -153,6 +153,6 @@ }, "WALLETS": { "ENABLED": true, - "WALLETS": ["BITB"] + "WALLETS": ["BITB", "3350"] } }