Merge branch 'master' into orangesurf/2024-07-19
This commit is contained in:
		
						commit
						811feec145
					
				@ -396,10 +396,6 @@ class Mempool {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public $updateAccelerations(newAccelerations: Acceleration[]): string[] {
 | 
					  public $updateAccelerations(newAccelerations: Acceleration[]): string[] {
 | 
				
			||||||
    if (!config.MEMPOOL_SERVICES.ACCELERATIONS) {
 | 
					 | 
				
			||||||
      return [];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const changed: string[] = [];
 | 
					      const changed: string[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import bitcoinClient from '../bitcoin/bitcoin-client';
 | 
				
			|||||||
import mining from "./mining";
 | 
					import mining from "./mining";
 | 
				
			||||||
import PricesRepository from '../../repositories/PricesRepository';
 | 
					import PricesRepository from '../../repositories/PricesRepository';
 | 
				
			||||||
import AccelerationRepository from '../../repositories/AccelerationRepository';
 | 
					import AccelerationRepository from '../../repositories/AccelerationRepository';
 | 
				
			||||||
 | 
					import accelerationApi from '../services/acceleration';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MiningRoutes {
 | 
					class MiningRoutes {
 | 
				
			||||||
  public initRoutes(app: Application) {
 | 
					  public initRoutes(app: Application) {
 | 
				
			||||||
@ -41,6 +42,8 @@ class MiningRoutes {
 | 
				
			|||||||
      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/block/:height', this.$getAccelerationsByHeight)
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/block/:height', this.$getAccelerationsByHeight)
 | 
				
			||||||
      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/recent/:interval', this.$getRecentAccelerations)
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/recent/:interval', this.$getRecentAccelerations)
 | 
				
			||||||
      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/total', this.$getAccelerationTotals)
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/total', this.$getAccelerationTotals)
 | 
				
			||||||
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations', this.$getActiveAccelerations)
 | 
				
			||||||
 | 
					      .post(config.MEMPOOL.API_URL_PREFIX + 'acceleration/request/:txid', this.$requestAcceleration)
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -445,6 +448,37 @@ class MiningRoutes {
 | 
				
			|||||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async $getActiveAccelerations(req: Request, res: Response): Promise<void> {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      res.header('Pragma', 'public');
 | 
				
			||||||
 | 
					      res.header('Cache-control', 'public');
 | 
				
			||||||
 | 
					      res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
 | 
				
			||||||
 | 
					      if (!config.MEMPOOL_SERVICES.ACCELERATIONS || ['testnet', 'signet', 'liquidtestnet', 'liquid'].includes(config.MEMPOOL.NETWORK)) {
 | 
				
			||||||
 | 
					        res.status(400).send('Acceleration data is not available.');
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      res.status(200).send(accelerationApi.accelerations || []);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async $requestAcceleration(req: Request, res: Response): Promise<void> {
 | 
				
			||||||
 | 
					    if (config.MEMPOOL_SERVICES.ACCELERATIONS || config.MEMPOOL.OFFICIAL) {
 | 
				
			||||||
 | 
					      res.status(405).send('not available.');
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    res.setHeader('Pragma', 'no-cache');
 | 
				
			||||||
 | 
					    res.setHeader('Cache-control', 'private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0');
 | 
				
			||||||
 | 
					    res.setHeader('expires', -1);
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      accelerationApi.accelerationRequested(req.params.txid);
 | 
				
			||||||
 | 
					      res.status(200).send('ok');
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new MiningRoutes();
 | 
					export default new MiningRoutes();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,10 @@
 | 
				
			|||||||
import config from '../../config';
 | 
					import config from '../../config';
 | 
				
			||||||
import logger from '../../logger';
 | 
					import logger from '../../logger';
 | 
				
			||||||
import { BlockExtended, PoolTag } from '../../mempool.interfaces';
 | 
					import { BlockExtended } from '../../mempool.interfaces';
 | 
				
			||||||
import axios from 'axios';
 | 
					import axios from 'axios';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MyAccelerationStatus = 'requested' | 'accelerating' | 'done';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Acceleration {
 | 
					export interface Acceleration {
 | 
				
			||||||
  txid: string,
 | 
					  txid: string,
 | 
				
			||||||
  added: number,
 | 
					  added: number,
 | 
				
			||||||
@ -35,18 +37,88 @@ export interface AccelerationHistory {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccelerationApi {
 | 
					class AccelerationApi {
 | 
				
			||||||
  public async $fetchAccelerations(): Promise<Acceleration[] | null> {
 | 
					  private apiPath = config.MEMPOOL.OFFICIAL ? (config.MEMPOOL_SERVICES.API + '/accelerator/accelerations') : (config.EXTERNAL_DATA_SERVER.MEMPOOL_API + '/accelerations');
 | 
				
			||||||
    if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
 | 
					  private _accelerations: Acceleration[] | null = null;
 | 
				
			||||||
 | 
					  private lastPoll = 0;
 | 
				
			||||||
 | 
					  private forcePoll = false;
 | 
				
			||||||
 | 
					  private myAccelerations: Record<string, { status: MyAccelerationStatus, added: number, acceleration?: Acceleration }> = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public get accelerations(): Acceleration[] | null {
 | 
				
			||||||
 | 
					    return this._accelerations;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public countMyAccelerationsWithStatus(filter: MyAccelerationStatus): number {
 | 
				
			||||||
 | 
					    return Object.values(this.myAccelerations).reduce((count, {status}) => { return count + (status === filter ? 1 : 0); }, 0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public accelerationRequested(txid: string): void {
 | 
				
			||||||
 | 
					    this.myAccelerations[txid] = { status: 'requested', added: Date.now() };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public accelerationConfirmed(): void {
 | 
				
			||||||
 | 
					    this.forcePoll = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async $fetchAccelerations(): Promise<Acceleration[] | null> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        const response = await axios.get(`${config.MEMPOOL_SERVICES.API}/accelerator/accelerations`, { responseType: 'json', timeout: 10000 });
 | 
					      const response = await axios.get(this.apiPath, { responseType: 'json', timeout: 10000 });
 | 
				
			||||||
        return response.data as Acceleration[];
 | 
					      return response?.data || [];
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      logger.warn('Failed to fetch current accelerations from the mempool services backend: ' + (e instanceof Error ? e.message : e));
 | 
					      logger.warn('Failed to fetch current accelerations from the mempool services backend: ' + (e instanceof Error ? e.message : e));
 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      return [];
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public async $updateAccelerations(): Promise<Acceleration[] | null> {
 | 
				
			||||||
 | 
					    if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
 | 
				
			||||||
 | 
					      const accelerations = await this.$fetchAccelerations();
 | 
				
			||||||
 | 
					      if (accelerations) {
 | 
				
			||||||
 | 
					        this._accelerations = accelerations;
 | 
				
			||||||
 | 
					        return this._accelerations;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return this.$updateAccelerationsOnDemand();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async $updateAccelerationsOnDemand(): Promise<Acceleration[] | null> {
 | 
				
			||||||
 | 
					    const shouldUpdate = this.forcePoll
 | 
				
			||||||
 | 
					      || this.countMyAccelerationsWithStatus('requested') > 0
 | 
				
			||||||
 | 
					      || (this.countMyAccelerationsWithStatus('accelerating') > 0 && this.lastPoll < (Date.now() - (10 * 60 * 1000)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // update accelerations if necessary
 | 
				
			||||||
 | 
					    if (shouldUpdate) {
 | 
				
			||||||
 | 
					      const accelerations = await this.$fetchAccelerations();
 | 
				
			||||||
 | 
					      this.lastPoll = Date.now();
 | 
				
			||||||
 | 
					      this.forcePoll = false;
 | 
				
			||||||
 | 
					      if (accelerations) {
 | 
				
			||||||
 | 
					        const latestAccelerations: Record<string, Acceleration> = {};
 | 
				
			||||||
 | 
					        // set relevant accelerations to 'accelerating'
 | 
				
			||||||
 | 
					        for (const acc of accelerations) {
 | 
				
			||||||
 | 
					          if (this.myAccelerations[acc.txid]) {
 | 
				
			||||||
 | 
					            latestAccelerations[acc.txid] = acc;
 | 
				
			||||||
 | 
					            this.myAccelerations[acc.txid] = { status: 'accelerating', added: Date.now(), acceleration: acc };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // txs that are no longer accelerating are either confirmed or canceled, so mark for expiry
 | 
				
			||||||
 | 
					        for (const [txid, { status, acceleration }] of Object.entries(this.myAccelerations)) {
 | 
				
			||||||
 | 
					          if (status === 'accelerating' && !latestAccelerations[txid]) {
 | 
				
			||||||
 | 
					            this.myAccelerations[txid] = { status: 'done', added: Date.now(), acceleration };
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // clear expired accelerations (confirmed / failed / not accepted) after 10 minutes
 | 
				
			||||||
 | 
					    for (const [txid, { status, added }] of Object.entries(this.myAccelerations)) {
 | 
				
			||||||
 | 
					      if (['requested', 'done'].includes(status) && added < (Date.now() - (1000 * 60 * 10))) {
 | 
				
			||||||
 | 
					        delete this.myAccelerations[txid];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this._accelerations = Object.values(this.myAccelerations).map(({ acceleration }) => acceleration).filter(acc => acc) as Acceleration[];
 | 
				
			||||||
 | 
					    return this._accelerations;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async $fetchAccelerationHistory(page?: number, status?: string): Promise<AccelerationHistory[] | null> {
 | 
					  public async $fetchAccelerationHistory(page?: number, status?: string): Promise<AccelerationHistory[] | null> {
 | 
				
			||||||
 | 
				
			|||||||
@ -538,9 +538,9 @@ class WebsocketHandler {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.MEMPOOL.RUST_GBT) {
 | 
					    if (config.MEMPOOL.RUST_GBT) {
 | 
				
			||||||
      await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, newMempool, added, removed, candidates, config.MEMPOOL_SERVICES.ACCELERATIONS);
 | 
					      await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, newMempool, added, removed, candidates, true);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      await mempoolBlocks.$updateBlockTemplates(transactionIds, newMempool, added, removed, candidates, accelerationDelta, true, config.MEMPOOL_SERVICES.ACCELERATIONS);
 | 
					      await mempoolBlocks.$updateBlockTemplates(transactionIds, newMempool, added, removed, candidates, accelerationDelta, true, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const mBlocks = mempoolBlocks.getMempoolBlocks();
 | 
					    const mBlocks = mempoolBlocks.getMempoolBlocks();
 | 
				
			||||||
@ -949,9 +949,8 @@ class WebsocketHandler {
 | 
				
			|||||||
    if (config.MEMPOOL.AUDIT && memPool.isInSync()) {
 | 
					    if (config.MEMPOOL.AUDIT && memPool.isInSync()) {
 | 
				
			||||||
      let projectedBlocks;
 | 
					      let projectedBlocks;
 | 
				
			||||||
      const auditMempool = _memPool;
 | 
					      const auditMempool = _memPool;
 | 
				
			||||||
      const isAccelerated = config.MEMPOOL_SERVICES.ACCELERATIONS && accelerationApi.isAcceleratedBlock(block, Object.values(mempool.getAccelerations()));
 | 
					      const isAccelerated = accelerationApi.isAcceleratedBlock(block, Object.values(mempool.getAccelerations()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if ((config.MEMPOOL_SERVICES.ACCELERATIONS)) {
 | 
					 | 
				
			||||||
      if (config.MEMPOOL.RUST_GBT) {
 | 
					      if (config.MEMPOOL.RUST_GBT) {
 | 
				
			||||||
        const added = memPool.limitGBT ? (candidates?.added || []) : [];
 | 
					        const added = memPool.limitGBT ? (candidates?.added || []) : [];
 | 
				
			||||||
        const removed = memPool.limitGBT ? (candidates?.removed || []) : [];
 | 
					        const removed = memPool.limitGBT ? (candidates?.removed || []) : [];
 | 
				
			||||||
@ -959,9 +958,6 @@ class WebsocketHandler {
 | 
				
			|||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        projectedBlocks = await mempoolBlocks.$makeBlockTemplates(transactionIds, auditMempool, candidates, false, isAccelerated, block.extras.pool.id);
 | 
					        projectedBlocks = await mempoolBlocks.$makeBlockTemplates(transactionIds, auditMempool, candidates, false, isAccelerated, block.extras.pool.id);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        projectedBlocks = mempoolBlocks.getMempoolBlocksWithTransactions();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (Common.indexingEnabled()) {
 | 
					      if (Common.indexingEnabled()) {
 | 
				
			||||||
        const { censored, added, prioritized, fresh, sigop, fullrbf, accelerated, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool);
 | 
					        const { censored, added, prioritized, fresh, sigop, fullrbf, accelerated, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool);
 | 
				
			||||||
@ -1040,7 +1036,7 @@ class WebsocketHandler {
 | 
				
			|||||||
      const removed = memPool.limitGBT ? (candidates?.removed || []) : transactions;
 | 
					      const removed = memPool.limitGBT ? (candidates?.removed || []) : transactions;
 | 
				
			||||||
      await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, _memPool, added, removed, candidates, true);
 | 
					      await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, _memPool, added, removed, candidates, true);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      await mempoolBlocks.$makeBlockTemplates(transactionIds, _memPool, candidates, true, config.MEMPOOL_SERVICES.ACCELERATIONS);
 | 
					      await mempoolBlocks.$makeBlockTemplates(transactionIds, _memPool, candidates, true, true);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const mBlocks = mempoolBlocks.getMempoolBlocks();
 | 
					    const mBlocks = mempoolBlocks.getMempoolBlocks();
 | 
				
			||||||
    const mBlockDeltas = mempoolBlocks.getMempoolBlockDeltas();
 | 
					    const mBlockDeltas = mempoolBlocks.getMempoolBlockDeltas();
 | 
				
			||||||
 | 
				
			|||||||
@ -229,7 +229,7 @@ class Server {
 | 
				
			|||||||
      const newMempool = await bitcoinApi.$getRawMempool();
 | 
					      const newMempool = await bitcoinApi.$getRawMempool();
 | 
				
			||||||
      const minFeeMempool = memPool.limitGBT ? await bitcoinSecondClient.getRawMemPool() : null;
 | 
					      const minFeeMempool = memPool.limitGBT ? await bitcoinSecondClient.getRawMemPool() : null;
 | 
				
			||||||
      const minFeeTip = memPool.limitGBT ? await bitcoinSecondClient.getBlockCount() : -1;
 | 
					      const minFeeTip = memPool.limitGBT ? await bitcoinSecondClient.getBlockCount() : -1;
 | 
				
			||||||
      const newAccelerations = await accelerationApi.$fetchAccelerations();
 | 
					      const newAccelerations = await accelerationApi.$updateAccelerations();
 | 
				
			||||||
      const numHandledBlocks = await blocks.$updateBlocks();
 | 
					      const numHandledBlocks = await blocks.$updateBlocks();
 | 
				
			||||||
      const pollRate = config.MEMPOOL.POLL_RATE_MS * (indexer.indexerIsRunning() ? 10 : 1);
 | 
					      const pollRate = config.MEMPOOL.POLL_RATE_MS * (indexer.indexerIsRunning() ? 10 : 1);
 | 
				
			||||||
      if (numHandledBlocks === 0) {
 | 
					      if (numHandledBlocks === 0) {
 | 
				
			||||||
 | 
				
			|||||||
@ -213,6 +213,15 @@ class AccelerationRepository {
 | 
				
			|||||||
        this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, successfulAccelerations);
 | 
					        this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, successfulAccelerations);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    let anyConfirmed = false;
 | 
				
			||||||
 | 
					    for (const acc of accelerations) {
 | 
				
			||||||
 | 
					      if (blockTxs[acc.txid]) {
 | 
				
			||||||
 | 
					        anyConfirmed = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (anyConfirmed) {
 | 
				
			||||||
 | 
					      accelerationApi.accelerationConfirmed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    const lastSyncedHeight = await this.$getLastSyncedHeight();
 | 
					    const lastSyncedHeight = await this.$getLastSyncedHeight();
 | 
				
			||||||
    // if we've missed any blocks, let the indexer catch up from the last synced height on the next run
 | 
					    // if we've missed any blocks, let the indexer catch up from the last synced height on the next run
 | 
				
			||||||
    if (block.height === lastSyncedHeight + 1) {
 | 
					    if (block.height === lastSyncedHeight + 1) {
 | 
				
			||||||
 | 
				
			|||||||
@ -40,6 +40,7 @@ __MAINNET_BLOCK_AUDIT_START_HEIGHT__=${MAINNET_BLOCK_AUDIT_START_HEIGHT:=0}
 | 
				
			|||||||
__TESTNET_BLOCK_AUDIT_START_HEIGHT__=${TESTNET_BLOCK_AUDIT_START_HEIGHT:=0}
 | 
					__TESTNET_BLOCK_AUDIT_START_HEIGHT__=${TESTNET_BLOCK_AUDIT_START_HEIGHT:=0}
 | 
				
			||||||
__SIGNET_BLOCK_AUDIT_START_HEIGHT__=${SIGNET_BLOCK_AUDIT_START_HEIGHT:=0}
 | 
					__SIGNET_BLOCK_AUDIT_START_HEIGHT__=${SIGNET_BLOCK_AUDIT_START_HEIGHT:=0}
 | 
				
			||||||
__ACCELERATOR__=${ACCELERATOR:=false}
 | 
					__ACCELERATOR__=${ACCELERATOR:=false}
 | 
				
			||||||
 | 
					__ACCELERATOR_BUTTON__=${ACCELERATOR_BUTTON:=true}
 | 
				
			||||||
__SERVICES_API__=${SERVICES_API:=false}
 | 
					__SERVICES_API__=${SERVICES_API:=false}
 | 
				
			||||||
__PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false}
 | 
					__PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false}
 | 
				
			||||||
__HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true}
 | 
					__HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true}
 | 
				
			||||||
@ -70,6 +71,7 @@ export __MAINNET_BLOCK_AUDIT_START_HEIGHT__
 | 
				
			|||||||
export __TESTNET_BLOCK_AUDIT_START_HEIGHT__
 | 
					export __TESTNET_BLOCK_AUDIT_START_HEIGHT__
 | 
				
			||||||
export __SIGNET_BLOCK_AUDIT_START_HEIGHT__
 | 
					export __SIGNET_BLOCK_AUDIT_START_HEIGHT__
 | 
				
			||||||
export __ACCELERATOR__
 | 
					export __ACCELERATOR__
 | 
				
			||||||
 | 
					export __ACCELERATOR_BUTTON__
 | 
				
			||||||
export __SERVICES_API__
 | 
					export __SERVICES_API__
 | 
				
			||||||
export __PUBLIC_ACCELERATIONS__
 | 
					export __PUBLIC_ACCELERATIONS__
 | 
				
			||||||
export __HISTORICAL_PRICE__
 | 
					export __HISTORICAL_PRICE__
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,7 @@
 | 
				
			|||||||
  "HISTORICAL_PRICE": true,
 | 
					  "HISTORICAL_PRICE": true,
 | 
				
			||||||
  "ADDITIONAL_CURRENCIES": false,
 | 
					  "ADDITIONAL_CURRENCIES": false,
 | 
				
			||||||
  "ACCELERATOR": false,
 | 
					  "ACCELERATOR": false,
 | 
				
			||||||
 | 
					  "ACCELERATOR_BUTTON": true,
 | 
				
			||||||
  "PUBLIC_ACCELERATIONS": false,
 | 
					  "PUBLIC_ACCELERATIONS": false,
 | 
				
			||||||
  "SERVICES_API": "https://mempool.space/api/v1/services"
 | 
					  "SERVICES_API": "https://mempool.space/api/v1/services"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -389,16 +389,22 @@
 | 
				
			|||||||
                  </div>
 | 
					                  </div>
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              @if (canPayWithCashapp) {
 | 
					              @if (canPayWithCashapp || canPayWithApplePay) {
 | 
				
			||||||
                <div class="col-sm text-center flex-grow-0  d-flex flex-column justify-content-center align-items-center">
 | 
					                <div class="col-sm text-center flex-grow-0  d-flex flex-column justify-content-center align-items-center">
 | 
				
			||||||
                  <p class="text-nowrap">—<span i18n="or">OR</span>—</p>
 | 
					                  <p class="text-nowrap">—<span i18n="or">OR</span>—</p>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            @if (canPayWithCashapp) {
 | 
					            @if (canPayWithCashapp || canPayWithApplePay) {
 | 
				
			||||||
              <div class="col-sm text-center d-flex flex-column justify-content-center align-items-center">
 | 
					              <div class="col-sm text-center d-flex flex-column justify-content-center align-items-center">
 | 
				
			||||||
                <p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container> <app-fiat [value]="cost"></app-fiat> with</p>
 | 
					                <p><ng-container i18n="transaction.pay|Pay button label">Pay</ng-container> <app-fiat [value]="cost"></app-fiat> with</p>
 | 
				
			||||||
                <img class="paymentMethod mx-2" src="/resources/cash-app.svg" height=55 (click)="moveToStep('cashapp')">
 | 
					                @if (canPayWithCashapp) {
 | 
				
			||||||
 | 
					                  <img class="paymentMethod mx-2" style="width: 200px" src="/resources/cash-app.svg" height=55 (click)="moveToStep('cashapp')">
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                @if (canPayWithApplePay) {
 | 
				
			||||||
 | 
					                  @if (canPayWithCashapp) { <hr class="w-25 mt-2 mb-2"> }
 | 
				
			||||||
 | 
					                  <img style="cursor: pointer;" src="/resources/apple-pay.svg" height=55 (click)="moveToStep('applepay')">
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
@ -421,9 +427,9 @@
 | 
				
			|||||||
        <button type="button" class="mt-1 btn btn-secondary btn-sm rounded-pill align-self-center" style="width: 200px" (click)="moveToStep('summary')" i18n="go-back">Go back</button>
 | 
					        <button type="button" class="mt-1 btn btn-secondary btn-sm rounded-pill align-self-center" style="width: 200px" (click)="moveToStep('summary')" i18n="go-back">Go back</button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  } @else if (step === 'cashapp') {
 | 
					  } @else if (step === 'cashapp' || step === 'applepay') {
 | 
				
			||||||
    <!-- Show checkout page -->
 | 
					    <!-- Show checkout page -->
 | 
				
			||||||
    <div class="row mb-md-1 text-center">
 | 
					    <div class="row mb-md-1 text-center" id="confirm-title">
 | 
				
			||||||
      <div class="col-sm" id="confirm-payment-title">
 | 
					      <div class="col-sm" id="confirm-payment-title">
 | 
				
			||||||
        <h1 style="font-size: larger;"><ng-content select="[slot='checkout-title']"></ng-content><span class="default-slot" i18n="accelerator.confirm-your-payment">Confirm your payment</span></h1>
 | 
					        <h1 style="font-size: larger;"><ng-content select="[slot='checkout-title']"></ng-content><span class="default-slot" i18n="accelerator.confirm-your-payment">Confirm your payment</span></h1>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
@ -437,7 +443,7 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @if (!loadingCashapp) {
 | 
					    @if (step === 'cashapp' && !loadingCashapp || step === 'applepay' && !loadingApplePay) {
 | 
				
			||||||
      <div class="row text-center mt-1">
 | 
					      <div class="row text-center mt-1">
 | 
				
			||||||
        <div class="col-sm">
 | 
					        <div class="col-sm">
 | 
				
			||||||
          <div class="form-group w-100">
 | 
					          <div class="form-group w-100">
 | 
				
			||||||
@ -456,8 +462,12 @@
 | 
				
			|||||||
    <div class="row text-center mt-1">
 | 
					    <div class="row text-center mt-1">
 | 
				
			||||||
      <div class="col-sm">
 | 
					      <div class="col-sm">
 | 
				
			||||||
        <div class="form-group w-100">
 | 
					        <div class="form-group w-100">
 | 
				
			||||||
 | 
					          @if (step === 'applepay') {
 | 
				
			||||||
 | 
					            <div id="apple-pay-button" class="apple-pay-button apple-pay-button-white" [style]="loadingApplePay ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div>
 | 
				
			||||||
 | 
					          } @else if (step === 'cashapp') {          
 | 
				
			||||||
            <div id="cash-app-pay" class="d-inline-block" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div>
 | 
					            <div id="cash-app-pay" class="d-inline-block" [style]="loadingCashapp ? 'opacity: 0; width: 0px; height: 0px; pointer-events: none;' : ''"></div>
 | 
				
			||||||
          @if (loadingCashapp) {
 | 
					          }
 | 
				
			||||||
 | 
					          @if (loadingCashapp || loadingApplePay) {
 | 
				
			||||||
          <div display="d-flex flex-row justify-content-center">
 | 
					          <div display="d-flex flex-row justify-content-center">
 | 
				
			||||||
            <span i18n="accelerator.loading-payment-method">Loading payment method...</span>
 | 
					            <span i18n="accelerator.loading-payment-method">Loading payment method...</span>
 | 
				
			||||||
            <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div>
 | 
					            <div class="ml-2 spinner-border text-light" style="width: 25px; height: 25px"></div>
 | 
				
			||||||
@ -549,7 +559,7 @@
 | 
				
			|||||||
  <button type="button" *ngIf="advancedEnabled" class="btn btn-sm btn-outline-info btn-small-height ml-2" (click)="moveToStep('quote')" i18n="accelerator.customize">customize</button>
 | 
					  <button type="button" *ngIf="advancedEnabled" class="btn btn-sm btn-outline-info btn-small-height ml-2" (click)="moveToStep('quote')" i18n="accelerator.customize">customize</button>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #accelerateTo let-x i18n="accelerator.accelerate-to-x">Accelerate to ~{{ x | number : '1.0-0' }} sat/vB</ng-template>
 | 
					<ng-template id="accelerate-to" #accelerateTo let-x i18n="accelerator.accelerate-to-x">Accelerate to ~{{ x | number : '1.0-0' }} sat/vB</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #accelerateButton>
 | 
					<ng-template #accelerateButton>
 | 
				
			||||||
  <div class="position-relative">
 | 
					  <div class="position-relative">
 | 
				
			||||||
 | 
				
			|||||||
@ -11,8 +11,7 @@
 | 
				
			|||||||
.paymentMethod {
 | 
					.paymentMethod {
 | 
				
			||||||
  padding: 10px;
 | 
					  padding: 10px;
 | 
				
			||||||
  background-color: var(--secondary);
 | 
					  background-color: var(--secondary);
 | 
				
			||||||
  border-radius: 15px;
 | 
					  border-radius: 10px;
 | 
				
			||||||
  border: 2px solid var(--bg);
 | 
					 | 
				
			||||||
  cursor: pointer;
 | 
					  cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -203,3 +202,18 @@
 | 
				
			|||||||
.btn-error-wrapper {
 | 
					.btn-error-wrapper {
 | 
				
			||||||
  height: 26px;
 | 
					  height: 26px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.apple-pay-button {
 | 
				
			||||||
 | 
					    display: inline-block;
 | 
				
			||||||
 | 
					    -webkit-appearance: -apple-pay-button;
 | 
				
			||||||
 | 
					    -apple-pay-button-type: plain; /* Use any supported button type. */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.apple-pay-button-black {
 | 
				
			||||||
 | 
					    -apple-pay-button-style: black;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.apple-pay-button-white {
 | 
				
			||||||
 | 
					    -apple-pay-button-style: white;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.apple-pay-button-white-with-line {
 | 
				
			||||||
 | 
					    -apple-pay-button-style: white-outline;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef, SimpleChanges, HostListener } from '@angular/core';
 | 
					import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef, SimpleChanges, HostListener } from '@angular/core';
 | 
				
			||||||
import { Subscription, tap, of, catchError, Observable, switchMap } from 'rxjs';
 | 
					import { Subscription, tap, of, catchError, Observable, switchMap } from 'rxjs';
 | 
				
			||||||
import { ServicesApiServices } from '../../services/services-api.service';
 | 
					import { ServicesApiServices } from '../../services/services-api.service';
 | 
				
			||||||
import { nextRoundNumber, insecureRandomUUID } from '../../shared/common.utils';
 | 
					import { md5, nextRoundNumber, insecureRandomUUID } from '../../shared/common.utils';
 | 
				
			||||||
import { StateService } from '../../services/state.service';
 | 
					import { StateService } from '../../services/state.service';
 | 
				
			||||||
import { AudioService } from '../../services/audio.service';
 | 
					import { AudioService } from '../../services/audio.service';
 | 
				
			||||||
import { ETA, EtaService } from '../../services/eta.service';
 | 
					import { ETA, EtaService } from '../../services/eta.service';
 | 
				
			||||||
@ -9,6 +9,7 @@ import { Transaction } from '../../interfaces/electrs.interface';
 | 
				
			|||||||
import { MiningStats } from '../../services/mining.service';
 | 
					import { MiningStats } from '../../services/mining.service';
 | 
				
			||||||
import { IAuth, AuthServiceMempool } from '../../services/auth.service';
 | 
					import { IAuth, AuthServiceMempool } from '../../services/auth.service';
 | 
				
			||||||
import { EnterpriseService } from '../../services/enterprise.service';
 | 
					import { EnterpriseService } from '../../services/enterprise.service';
 | 
				
			||||||
 | 
					import { ApiService } from '../../services/api.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp';
 | 
					export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -46,7 +47,7 @@ export const MIN_BID_RATIO = 1;
 | 
				
			|||||||
export const DEFAULT_BID_RATIO = 2;
 | 
					export const DEFAULT_BID_RATIO = 2;
 | 
				
			||||||
export const MAX_BID_RATIO = 4;
 | 
					export const MAX_BID_RATIO = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'processing' | 'paid' | 'success';
 | 
					type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'applepay' | 'processing' | 'paid' | 'success';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-accelerate-checkout',
 | 
					  selector: 'app-accelerate-checkout',
 | 
				
			||||||
@ -60,6 +61,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
  @Input() eta: ETA;
 | 
					  @Input() eta: ETA;
 | 
				
			||||||
  @Input() scrollEvent: boolean;
 | 
					  @Input() scrollEvent: boolean;
 | 
				
			||||||
  @Input() cashappEnabled: boolean = true;
 | 
					  @Input() cashappEnabled: boolean = true;
 | 
				
			||||||
 | 
					  @Input() applePayEnabled: boolean = false;
 | 
				
			||||||
  @Input() advancedEnabled: boolean = false;
 | 
					  @Input() advancedEnabled: boolean = false;
 | 
				
			||||||
  @Input() forceMobile: boolean = false;
 | 
					  @Input() forceMobile: boolean = false;
 | 
				
			||||||
  @Input() showDetails: boolean = false;
 | 
					  @Input() showDetails: boolean = false;
 | 
				
			||||||
@ -109,11 +111,12 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // square
 | 
					  // square
 | 
				
			||||||
  loadingCashapp = false;
 | 
					  loadingCashapp = false;
 | 
				
			||||||
 | 
					  loadingApplePay = false;
 | 
				
			||||||
  cashappError = false;
 | 
					  cashappError = false;
 | 
				
			||||||
  cashappSubmit: any;
 | 
					  cashappSubmit: any;
 | 
				
			||||||
  payments: any;
 | 
					  payments: any;
 | 
				
			||||||
  cashAppPay: any;
 | 
					  cashAppPay: any;
 | 
				
			||||||
  cashAppSubscription: Subscription;
 | 
					  applePay: any;
 | 
				
			||||||
  conversionsSubscription: Subscription;
 | 
					  conversionsSubscription: Subscription;
 | 
				
			||||||
  conversions: any;
 | 
					  conversions: any;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
@ -123,6 +126,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    public stateService: StateService,
 | 
					    public stateService: StateService,
 | 
				
			||||||
 | 
					    private apiService: ApiService,
 | 
				
			||||||
    private servicesApiService: ServicesApiServices,
 | 
					    private servicesApiService: ServicesApiServices,
 | 
				
			||||||
    private etaService: EtaService,
 | 
					    private etaService: EtaService,
 | 
				
			||||||
    private audioService: AudioService,
 | 
					    private audioService: AudioService,
 | 
				
			||||||
@ -131,6 +135,12 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
    private enterpriseService: EnterpriseService,
 | 
					    private enterpriseService: EnterpriseService,
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    this.accelerationUUID = insecureRandomUUID();
 | 
					    this.accelerationUUID = insecureRandomUUID();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check if Apple Pay available
 | 
				
			||||||
 | 
					    // @ts-ignore https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/checking_for_apple_pay_availability#overview
 | 
				
			||||||
 | 
					    if (window.ApplePaySession) {
 | 
				
			||||||
 | 
					      this.applePayEnabled = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit() {
 | 
					  ngOnInit() {
 | 
				
			||||||
@ -212,6 +222,12 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
      this.loadingCashapp = true;
 | 
					      this.loadingCashapp = true;
 | 
				
			||||||
      this.insertSquare();
 | 
					      this.insertSquare();
 | 
				
			||||||
      this.setupSquare();
 | 
					      this.setupSquare();
 | 
				
			||||||
 | 
					      this.scrollToElementWithTimeout('confirm-title', 'center', 100);
 | 
				
			||||||
 | 
					    } else if (this._step === 'applepay' && this.applePayEnabled) {
 | 
				
			||||||
 | 
					      this.loadingApplePay = true;
 | 
				
			||||||
 | 
					      this.insertSquare();
 | 
				
			||||||
 | 
					      this.setupSquare();
 | 
				
			||||||
 | 
					      this.scrollToElementWithTimeout('confirm-title', 'center', 100);
 | 
				
			||||||
    } else if (this._step === 'paid') {
 | 
					    } else if (this._step === 'paid') {
 | 
				
			||||||
      this.timePaid = Date.now();
 | 
					      this.timePaid = Date.now();
 | 
				
			||||||
      this.timeoutTimer = setTimeout(() => {
 | 
					      this.timeoutTimer = setTimeout(() => {
 | 
				
			||||||
@ -370,10 +386,11 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
      this.accelerationUUID
 | 
					      this.accelerationUUID
 | 
				
			||||||
    ).subscribe({
 | 
					    ).subscribe({
 | 
				
			||||||
      next: () => {
 | 
					      next: () => {
 | 
				
			||||||
 | 
					        this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
 | 
				
			||||||
        this.audioService.playSound('ascend-chime-cartoon');
 | 
					        this.audioService.playSound('ascend-chime-cartoon');
 | 
				
			||||||
        this.showSuccess = true;
 | 
					        this.showSuccess = true;
 | 
				
			||||||
        this.estimateSubscription.unsubscribe();
 | 
					        this.estimateSubscription.unsubscribe();
 | 
				
			||||||
        this.moveToStep('paid')
 | 
					        this.moveToStep('paid');
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      error: (response) => {
 | 
					      error: (response) => {
 | 
				
			||||||
        this.accelerateError = response.error;
 | 
					        this.accelerateError = response.error;
 | 
				
			||||||
@ -421,17 +438,113 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      //@ts-ignore
 | 
					      //@ts-ignore
 | 
				
			||||||
      this.payments = window.Square.payments(this.square.appId, this.square.locationId)
 | 
					      this.payments = window.Square.payments(this.square.appId, this.square.locationId)
 | 
				
			||||||
 | 
					      const urlParams = new URLSearchParams(window.location.search);
 | 
				
			||||||
 | 
					      if (this._step === 'cashapp' || urlParams.get('cash_request_id')) {
 | 
				
			||||||
        await this.requestCashAppPayment();
 | 
					        await this.requestCashAppPayment();
 | 
				
			||||||
 | 
					      } else if (this._step === 'applepay') {
 | 
				
			||||||
 | 
					        await this.requestApplePayPayment();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      console.debug('Error loading Square Payments', e);
 | 
					      console.debug('Error loading Square Payments', e);
 | 
				
			||||||
      this.cashappError = true;
 | 
					      this.cashappError = true;
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  async requestCashAppPayment() {
 | 
					
 | 
				
			||||||
    if (this.cashAppSubscription) {
 | 
					  /**
 | 
				
			||||||
      this.cashAppSubscription.unsubscribe();
 | 
					   * APPLE PAY
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  async requestApplePayPayment() {
 | 
				
			||||||
 | 
					    if (this.conversionsSubscription) {
 | 
				
			||||||
 | 
					      this.conversionsSubscription.unsubscribe();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    this.conversionsSubscription = this.stateService.conversions$.subscribe(
 | 
				
			||||||
 | 
					      async (conversions) => {
 | 
				
			||||||
 | 
					        this.conversions = conversions;
 | 
				
			||||||
 | 
					        if (this.applePay) {
 | 
				
			||||||
 | 
					          this.applePay.destroy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const costUSD = this.cost / 100_000_000 * conversions.USD;
 | 
				
			||||||
 | 
					        const paymentRequest = this.payments.paymentRequest({
 | 
				
			||||||
 | 
					          countryCode: 'US',
 | 
				
			||||||
 | 
					          currencyCode: 'USD',
 | 
				
			||||||
 | 
					          total: {
 | 
				
			||||||
 | 
					            amount: costUSD.toFixed(2),
 | 
				
			||||||
 | 
					            label: 'Total',
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					          this.applePay = await this.payments.applePay(paymentRequest);
 | 
				
			||||||
 | 
					          const applePayButton = document.getElementById('apple-pay-button');
 | 
				
			||||||
 | 
					          if (!applePayButton) {
 | 
				
			||||||
 | 
					            console.error(`Unable to find apple pay button id='apple-pay-button'`);
 | 
				
			||||||
 | 
					            // Try again
 | 
				
			||||||
 | 
					            setTimeout(this.requestApplePayPayment.bind(this), 500);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          this.loadingApplePay = false;
 | 
				
			||||||
 | 
					          applePayButton.addEventListener('click', async event => {
 | 
				
			||||||
 | 
					            event.preventDefault();
 | 
				
			||||||
 | 
					            const tokenResult = await this.applePay.tokenize();
 | 
				
			||||||
 | 
					            if (tokenResult?.status === 'OK') {
 | 
				
			||||||
 | 
					              const card = tokenResult.details?.card;
 | 
				
			||||||
 | 
					              if (!card || !card.brand || !card.expMonth || !card.expYear || !card.last4) {
 | 
				
			||||||
 | 
					                console.error(`Cannot retreive payment card details`);
 | 
				
			||||||
 | 
					                this.accelerateError = 'apple_pay_no_card_details';
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              const cardTag = md5(`${card.brand}${card.expMonth}${card.expYear}${card.last4}`.toLowerCase());
 | 
				
			||||||
 | 
					              this.servicesApiService.accelerateWithApplePay$(
 | 
				
			||||||
 | 
					                this.tx.txid,
 | 
				
			||||||
 | 
					                tokenResult.token,
 | 
				
			||||||
 | 
					                cardTag,
 | 
				
			||||||
 | 
					                `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`,
 | 
				
			||||||
 | 
					                this.accelerationUUID
 | 
				
			||||||
 | 
					              ).subscribe({
 | 
				
			||||||
 | 
					                next: () => {
 | 
				
			||||||
 | 
					                  this.audioService.playSound('ascend-chime-cartoon');
 | 
				
			||||||
 | 
					                  if (this.applePay) {
 | 
				
			||||||
 | 
					                    this.applePay.destroy();
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  setTimeout(() => {
 | 
				
			||||||
 | 
					                    this.moveToStep('paid');
 | 
				
			||||||
 | 
					                  }, 1000);
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                error: (response) => {
 | 
				
			||||||
 | 
					                  this.accelerateError = response.error;
 | 
				
			||||||
 | 
					                  if (!(response.status === 403 && response.error === 'not_available')) {
 | 
				
			||||||
 | 
					                    setTimeout(() => {
 | 
				
			||||||
 | 
					                      // Reset everything by reloading the page :D, can be improved
 | 
				
			||||||
 | 
					                      const urlParams = new URLSearchParams(window.location.search);
 | 
				
			||||||
 | 
					                      window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``));
 | 
				
			||||||
 | 
					                    }, 3000);
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              let errorMessage = `Tokenization failed with status: ${tokenResult.status}`;
 | 
				
			||||||
 | 
					              if (tokenResult.errors) {
 | 
				
			||||||
 | 
					                errorMessage += ` and errors: ${JSON.stringify(
 | 
				
			||||||
 | 
					                  tokenResult.errors,
 | 
				
			||||||
 | 
					                )}`;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              throw new Error(errorMessage);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					          console.error(e);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * CASHAPP
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  async requestCashAppPayment() {
 | 
				
			||||||
    if (this.conversionsSubscription) {
 | 
					    if (this.conversionsSubscription) {
 | 
				
			||||||
      this.conversionsSubscription.unsubscribe();
 | 
					      this.conversionsSubscription.unsubscribe();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -449,7 +562,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
          countryCode: 'US',
 | 
					          countryCode: 'US',
 | 
				
			||||||
          currencyCode: 'USD',
 | 
					          currencyCode: 'USD',
 | 
				
			||||||
          total: {
 | 
					          total: {
 | 
				
			||||||
            amount: costUSD.toString(),
 | 
					            amount: costUSD.toFixed(2),
 | 
				
			||||||
            label: 'Total',
 | 
					            label: 'Total',
 | 
				
			||||||
            pending: true,
 | 
					            pending: true,
 | 
				
			||||||
            productUrl: `${redirectHostname}/tracker/${this.tx.txid}`,
 | 
					            productUrl: `${redirectHostname}/tracker/${this.tx.txid}`,
 | 
				
			||||||
@ -467,23 +580,23 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        this.loadingCashapp = false;
 | 
					        this.loadingCashapp = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const that = this;
 | 
					        this.cashAppPay.addEventListener('ontokenization', event => {
 | 
				
			||||||
        this.cashAppPay.addEventListener('ontokenization', function (event) {
 | 
					 | 
				
			||||||
          const { tokenResult, error } = event.detail;
 | 
					          const { tokenResult, error } = event.detail;
 | 
				
			||||||
          if (error) {
 | 
					          if (error) {
 | 
				
			||||||
            this.accelerateError = error;
 | 
					            this.accelerateError = error;
 | 
				
			||||||
          } else if (tokenResult.status === 'OK') {
 | 
					          } else if (tokenResult.status === 'OK') {
 | 
				
			||||||
            that.servicesApiService.accelerateWithCashApp$(
 | 
					            this.servicesApiService.accelerateWithCashApp$(
 | 
				
			||||||
              that.tx.txid,
 | 
					              this.tx.txid,
 | 
				
			||||||
              tokenResult.token,
 | 
					              tokenResult.token,
 | 
				
			||||||
              tokenResult.details.cashAppPay.cashtag,
 | 
					              tokenResult.details.cashAppPay.cashtag,
 | 
				
			||||||
              tokenResult.details.cashAppPay.referenceId,
 | 
					              tokenResult.details.cashAppPay.referenceId,
 | 
				
			||||||
              that.accelerationUUID
 | 
					              this.accelerationUUID
 | 
				
			||||||
            ).subscribe({
 | 
					            ).subscribe({
 | 
				
			||||||
              next: () => {
 | 
					              next: () => {
 | 
				
			||||||
                that.audioService.playSound('ascend-chime-cartoon');
 | 
					                this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
 | 
				
			||||||
                if (that.cashAppPay) {
 | 
					                this.audioService.playSound('ascend-chime-cartoon');
 | 
				
			||||||
                  that.cashAppPay.destroy();
 | 
					                if (this.cashAppPay) {
 | 
				
			||||||
 | 
					                  this.cashAppPay.destroy();
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                setTimeout(() => {
 | 
					                setTimeout(() => {
 | 
				
			||||||
                  this.moveToStep('paid');
 | 
					                  this.moveToStep('paid');
 | 
				
			||||||
@ -494,7 +607,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
                }, 1000);
 | 
					                }, 1000);
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
              error: (response) => {
 | 
					              error: (response) => {
 | 
				
			||||||
                that.accelerateError = response.error;
 | 
					                this.accelerateError = response.error;
 | 
				
			||||||
                if (!(response.status === 403 && response.error === 'not_available')) {
 | 
					                if (!(response.status === 403 && response.error === 'not_available')) {
 | 
				
			||||||
                  setTimeout(() => {
 | 
					                  setTimeout(() => {
 | 
				
			||||||
                    // Reset everything by reloading the page :D, can be improved
 | 
					                    // Reset everything by reloading the page :D, can be improved
 | 
				
			||||||
@ -530,9 +643,10 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bitcoinPaymentCompleted(): void {
 | 
					  bitcoinPaymentCompleted(): void {
 | 
				
			||||||
 | 
					    this.apiService.logAccelerationRequest$(this.tx.txid).subscribe();
 | 
				
			||||||
    this.audioService.playSound('ascend-chime-cartoon');
 | 
					    this.audioService.playSound('ascend-chime-cartoon');
 | 
				
			||||||
    this.estimateSubscription.unsubscribe();
 | 
					    this.estimateSubscription.unsubscribe();
 | 
				
			||||||
    this.moveToStep('paid')
 | 
					    this.moveToStep('paid');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  isLoggedIn(): boolean {
 | 
					  isLoggedIn(): boolean {
 | 
				
			||||||
@ -565,6 +679,13 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
    return !!this.estimate?.availablePaymentMethods?.cashapp;
 | 
					    return !!this.estimate?.availablePaymentMethods?.cashapp;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get couldPayWithApplePay() {
 | 
				
			||||||
 | 
					    if (!this.applePayEnabled) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return !!this.estimate?.availablePaymentMethods?.applePay;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get couldPayWithBalance() {
 | 
					  get couldPayWithBalance() {
 | 
				
			||||||
    if (!this.hasAccessToBalanceMode) {
 | 
					    if (!this.hasAccessToBalanceMode) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
@ -573,7 +694,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get couldPay() {
 | 
					  get couldPay() {
 | 
				
			||||||
    return this.couldPayWithBalance || this.couldPayWithBitcoin || this.couldPayWithCashapp;
 | 
					    return this.couldPayWithBalance || this.couldPayWithBitcoin || this.couldPayWithCashapp || this.couldPayWithApplePay;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get canPayWithBitcoin() {
 | 
					  get canPayWithBitcoin() {
 | 
				
			||||||
@ -597,6 +718,22 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  get canPayWithApplePay() {
 | 
				
			||||||
 | 
					    if (!this.applePayEnabled || !this.conversions) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const paymentMethod = this.estimate?.availablePaymentMethods?.applePay;
 | 
				
			||||||
 | 
					    if (paymentMethod) {
 | 
				
			||||||
 | 
					      const costUSD = (this.cost / 100_000_000 * this.conversions.USD);
 | 
				
			||||||
 | 
					      if (costUSD >= paymentMethod.min && costUSD <= paymentMethod.max) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get canPayWithBalance() {
 | 
					  get canPayWithBalance() {
 | 
				
			||||||
    if (!this.hasAccessToBalanceMode) {
 | 
					    if (!this.hasAccessToBalanceMode) {
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
@ -606,7 +743,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get canPay() {
 | 
					  get canPay() {
 | 
				
			||||||
    return this.canPayWithBalance || this.canPayWithBitcoin || this.canPayWithCashapp;
 | 
					    return this.canPayWithBalance || this.canPayWithBitcoin || this.canPayWithCashapp || this.canPayWithApplePay;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get hasAccessToBalanceMode() {
 | 
					  get hasAccessToBalanceMode() {
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@
 | 
				
			|||||||
        <ng-container *ngIf="!pending">
 | 
					        <ng-container *ngIf="!pending">
 | 
				
			||||||
          <th class="fee text-right" i18n="transaction.bid-boost|Bid Boost">Bid Boost</th>
 | 
					          <th class="fee text-right" i18n="transaction.bid-boost|Bid Boost">Bid Boost</th>
 | 
				
			||||||
          <th class="block text-right" i18n="shared.block-title">Block</th>
 | 
					          <th class="block text-right" i18n="shared.block-title">Block</th>
 | 
				
			||||||
 | 
					          <th class="pool text-right" i18n="mining.pool-name" *ngIf="!this.widget">Pool</th>
 | 
				
			||||||
          <th class="status text-right" i18n="transaction.status|Transaction Status">Status</th>
 | 
					          <th class="status text-right" i18n="transaction.status|Transaction Status">Status</th>
 | 
				
			||||||
          <th class="date text-right" i18n="accelerator.requested" *ngIf="!this.widget">Requested</th>
 | 
					          <th class="date text-right" i18n="accelerator.requested" *ngIf="!this.widget">Requested</th>
 | 
				
			||||||
        </ng-container>
 | 
					        </ng-container>
 | 
				
			||||||
@ -49,6 +50,16 @@
 | 
				
			|||||||
              <a *ngIf="acceleration.blockHeight" [routerLink]="['/block' | relativeUrl, acceleration.blockHeight]">{{ acceleration.blockHeight }}</a>
 | 
					              <a *ngIf="acceleration.blockHeight" [routerLink]="['/block' | relativeUrl, acceleration.blockHeight]">{{ acceleration.blockHeight }}</a>
 | 
				
			||||||
              <span *ngIf="!acceleration.blockHeight">~</span>
 | 
					              <span *ngIf="!acceleration.blockHeight">~</span>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
 | 
					            <td class="pool text-right" *ngIf="!this.widget">
 | 
				
			||||||
 | 
					              @if (acceleration.minedByPoolUniqueId && pools[acceleration.minedByPoolUniqueId]) {
 | 
				
			||||||
 | 
					                <a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, pools[acceleration.minedByPoolUniqueId].slug]" class="badge" style="color: #FFF;padding:0;">
 | 
				
			||||||
 | 
					                  <img class="pool-logo" [src]="'/resources/mining-pools/' + pools[acceleration.minedByPoolUniqueId].slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + pools[acceleration.minedByPoolUniqueId].name + ' mining pool'">
 | 
				
			||||||
 | 
					                  {{ pools[acceleration.minedByPoolUniqueId].name }}
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					              } @else {
 | 
				
			||||||
 | 
					                ~
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
            <td class="status text-right">
 | 
					            <td class="status text-right">
 | 
				
			||||||
              <span *ngIf="acceleration.status === 'accelerating'" class="badge badge-warning" i18n="accelerator.pending">Pending</span>
 | 
					              <span *ngIf="acceleration.status === 'accelerating'" class="badge badge-warning" i18n="accelerator.pending">Pending</span>
 | 
				
			||||||
              <span *ngIf="acceleration.status.includes('completed')" class="badge badge-success" i18n="">Completed <span *ngIf="acceleration.status === 'completed_provisional'">🔄</span></span>
 | 
					              <span *ngIf="acceleration.status.includes('completed')" class="badge badge-success" i18n="">Completed <span *ngIf="acceleration.status === 'completed_provisional'">🔄</span></span>
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@
 | 
				
			|||||||
  padding-bottom: 0px;
 | 
					  padding-bottom: 0px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.container-xl.legacy {
 | 
					.container-xl.legacy {
 | 
				
			||||||
  max-width: 1140px;
 | 
					  max-width: 1200px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
.container-xl.widget-container {
 | 
					.container-xl.widget-container {
 | 
				
			||||||
  min-height: 335px;
 | 
					  min-height: 335px;
 | 
				
			||||||
@ -72,9 +72,25 @@ tr, td, th {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.block {
 | 
					.block {
 | 
				
			||||||
  width: 15%;
 | 
					  width: 15%;
 | 
				
			||||||
 | 
					  @media (max-width: 900px) {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pool {
 | 
				
			||||||
 | 
					  width: 15%;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  @media (max-width: 700px) {
 | 
					  @media (max-width: 700px) {
 | 
				
			||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .pool-logo {
 | 
				
			||||||
 | 
					    width: 22px;
 | 
				
			||||||
 | 
					    height: 22px;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    top: -1px;
 | 
				
			||||||
 | 
					    margin-right: 2px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.status {
 | 
					.status {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,12 @@
 | 
				
			|||||||
import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy, Inject, LOCALE_ID } from '@angular/core';
 | 
					import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy, Inject, LOCALE_ID } from '@angular/core';
 | 
				
			||||||
import { BehaviorSubject, Observable, Subscription, catchError, filter, of, switchMap, tap, throttleTime } from 'rxjs';
 | 
					import { BehaviorSubject, Observable, Subscription, catchError, filter, of, switchMap, tap, throttleTime } from 'rxjs';
 | 
				
			||||||
import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
 | 
					import { Acceleration, BlockExtended, SinglePoolStats } from '../../../interfaces/node-api.interface';
 | 
				
			||||||
import { StateService } from '../../../services/state.service';
 | 
					import { StateService } from '../../../services/state.service';
 | 
				
			||||||
import { WebsocketService } from '../../../services/websocket.service';
 | 
					import { WebsocketService } from '../../../services/websocket.service';
 | 
				
			||||||
import { ServicesApiServices } from '../../../services/services-api.service';
 | 
					import { ServicesApiServices } from '../../../services/services-api.service';
 | 
				
			||||||
import { SeoService } from '../../../services/seo.service';
 | 
					import { SeoService } from '../../../services/seo.service';
 | 
				
			||||||
import { ActivatedRoute, Router } from '@angular/router';
 | 
					import { ActivatedRoute, Router } from '@angular/router';
 | 
				
			||||||
 | 
					import { MiningService } from '../../../services/mining.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-accelerations-list',
 | 
					  selector: 'app-accelerations-list',
 | 
				
			||||||
@ -30,11 +31,13 @@ export class AccelerationsListComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
  keyNavigationSubscription: Subscription;
 | 
					  keyNavigationSubscription: Subscription;
 | 
				
			||||||
  dir: 'rtl' | 'ltr' = 'ltr';
 | 
					  dir: 'rtl' | 'ltr' = 'ltr';
 | 
				
			||||||
  paramSubscription: Subscription;
 | 
					  paramSubscription: Subscription;
 | 
				
			||||||
 | 
					  pools: { [id: number]: SinglePoolStats } = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    private servicesApiService: ServicesApiServices,
 | 
					    private servicesApiService: ServicesApiServices,
 | 
				
			||||||
    private websocketService: WebsocketService,
 | 
					    private websocketService: WebsocketService,
 | 
				
			||||||
    public stateService: StateService,
 | 
					    public stateService: StateService,
 | 
				
			||||||
 | 
					    private miningService: MiningService,
 | 
				
			||||||
    private cd: ChangeDetectorRef,
 | 
					    private cd: ChangeDetectorRef,
 | 
				
			||||||
    private seoService: SeoService,
 | 
					    private seoService: SeoService,
 | 
				
			||||||
    private route: ActivatedRoute,
 | 
					    private route: ActivatedRoute,
 | 
				
			||||||
@ -79,6 +82,12 @@ export class AccelerationsListComponent implements OnInit, OnDestroy {
 | 
				
			|||||||
      ).subscribe(() => {
 | 
					      ).subscribe(() => {
 | 
				
			||||||
        this.pageChange(this.page);
 | 
					        this.pageChange(this.page);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.miningService.getMiningStats('1m').subscribe(stats => {
 | 
				
			||||||
 | 
					        for (const pool of stats.pools) {
 | 
				
			||||||
 | 
					          this.pools[pool.poolUniqueId] = pool;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()];
 | 
					    this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()];
 | 
				
			||||||
 | 
				
			|||||||
@ -249,7 +249,7 @@
 | 
				
			|||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #pendingBalanceRow>
 | 
					<ng-template #pendingBalanceRow>
 | 
				
			||||||
  <td i18n="address.unconfirmed-balance" class="font-italic">Unconfirmed balance</td>
 | 
					  <td i18n="accelerator.pending-state" class="font-italic">Pending</td>
 | 
				
			||||||
  <td *ngIf="mempoolStats.funded_txo_sum !== undefined; else confidentialTd" class="font-italic wrap-cell"><app-amount [satoshis]="mempoolStats.balance" [noFiat]="true" [addPlus]="true"></app-amount> <span class="fiat"><app-fiat [value]="mempoolStats.balance"></app-fiat></span></td>
 | 
					  <td *ngIf="mempoolStats.funded_txo_sum !== undefined; else confidentialTd" class="font-italic wrap-cell"><app-amount [satoshis]="mempoolStats.balance" [noFiat]="true" [addPlus]="true"></app-amount> <span class="fiat"><app-fiat [value]="mempoolStats.balance"></app-fiat></span></td>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -259,7 +259,7 @@
 | 
				
			|||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<ng-template #pendingUtxoRow>
 | 
					<ng-template #pendingUtxoRow>
 | 
				
			||||||
  <td i18n="address.unconfirmed-utxos" class="font-italic">Unconfirmed UTXOs</td>
 | 
					  <td i18n="address.pending-utxos" class="font-italic">Pending UTXOs</td>
 | 
				
			||||||
  <td class="font-italic wrap-cell">{{ mempoolStats.utxos > 0 ? '+' : ''}}{{ mempoolStats.utxos }}</td>
 | 
					  <td class="font-italic wrap-cell">{{ mempoolStats.utxos > 0 ? '+' : ''}}{{ mempoolStats.utxos }}</td>
 | 
				
			||||||
</ng-template>
 | 
					</ng-template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -303,7 +303,6 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
          (error) => { console.log(error); this.isSearching = false; }
 | 
					          (error) => { console.log(error); this.isSearching = false; }
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        this.searchResults.searchButtonClick();
 | 
					 | 
				
			||||||
        this.isSearching = false;
 | 
					        this.isSearching = false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -234,7 +234,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy {
 | 
				
			|||||||
    this.minScrollWidth = 40 + (8 * this.blockWidth) + (this.pageWidth * 2);
 | 
					    this.minScrollWidth = 40 + (8 * this.blockWidth) + (this.pageWidth * 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (firstVisibleBlock != null) {
 | 
					    if (firstVisibleBlock != null) {
 | 
				
			||||||
      this.scrollToBlock(firstVisibleBlock, offset);
 | 
					      this.scrollToBlock(firstVisibleBlock, offset + (this.isMobile ? this.blockWidth : 0));
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.updatePages();
 | 
					      this.updatePages();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,9 @@ import {
 | 
				
			|||||||
  tap,
 | 
					  tap,
 | 
				
			||||||
  map,
 | 
					  map,
 | 
				
			||||||
  retry,
 | 
					  retry,
 | 
				
			||||||
  startWith
 | 
					  startWith,
 | 
				
			||||||
 | 
					  repeat,
 | 
				
			||||||
 | 
					  take
 | 
				
			||||||
} from 'rxjs/operators';
 | 
					} from 'rxjs/operators';
 | 
				
			||||||
import { Transaction } from '../../interfaces/electrs.interface';
 | 
					import { Transaction } from '../../interfaces/electrs.interface';
 | 
				
			||||||
import { of, merge, Subscription, Observable, Subject, from, throwError, combineLatest, BehaviorSubject } from 'rxjs';
 | 
					import { of, merge, Subscription, Observable, Subject, from, throwError, combineLatest, BehaviorSubject } from 'rxjs';
 | 
				
			||||||
@ -76,6 +78,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
  transactionTime = -1;
 | 
					  transactionTime = -1;
 | 
				
			||||||
  subscription: Subscription;
 | 
					  subscription: Subscription;
 | 
				
			||||||
  fetchCpfpSubscription: Subscription;
 | 
					  fetchCpfpSubscription: Subscription;
 | 
				
			||||||
 | 
					  transactionTimesSubscription: Subscription;
 | 
				
			||||||
  fetchRbfSubscription: Subscription;
 | 
					  fetchRbfSubscription: Subscription;
 | 
				
			||||||
  fetchCachedTxSubscription: Subscription;
 | 
					  fetchCachedTxSubscription: Subscription;
 | 
				
			||||||
  fetchAccelerationSubscription: Subscription;
 | 
					  fetchAccelerationSubscription: Subscription;
 | 
				
			||||||
@ -88,6 +91,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
  blocksSubscription: Subscription;
 | 
					  blocksSubscription: Subscription;
 | 
				
			||||||
  miningSubscription: Subscription;
 | 
					  miningSubscription: Subscription;
 | 
				
			||||||
  auditSubscription: Subscription;
 | 
					  auditSubscription: Subscription;
 | 
				
			||||||
 | 
					  txConfirmedSubscription: Subscription;
 | 
				
			||||||
  currencyChangeSubscription: Subscription;
 | 
					  currencyChangeSubscription: Subscription;
 | 
				
			||||||
  fragmentParams: URLSearchParams;
 | 
					  fragmentParams: URLSearchParams;
 | 
				
			||||||
  rbfTransaction: undefined | Transaction;
 | 
					  rbfTransaction: undefined | Transaction;
 | 
				
			||||||
@ -106,6 +110,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
  showCpfpDetails = false;
 | 
					  showCpfpDetails = false;
 | 
				
			||||||
  miningStats: MiningStats;
 | 
					  miningStats: MiningStats;
 | 
				
			||||||
  fetchCpfp$ = new Subject<string>();
 | 
					  fetchCpfp$ = new Subject<string>();
 | 
				
			||||||
 | 
					  transactionTimes$ = new Subject<string>();
 | 
				
			||||||
  fetchRbfHistory$ = new Subject<string>();
 | 
					  fetchRbfHistory$ = new Subject<string>();
 | 
				
			||||||
  fetchCachedTx$ = new Subject<string>();
 | 
					  fetchCachedTx$ = new Subject<string>();
 | 
				
			||||||
  fetchAcceleration$ = new Subject<number>();
 | 
					  fetchAcceleration$ = new Subject<number>();
 | 
				
			||||||
@ -141,7 +146,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
  taprootEnabled: boolean;
 | 
					  taprootEnabled: boolean;
 | 
				
			||||||
  hasEffectiveFeeRate: boolean;
 | 
					  hasEffectiveFeeRate: boolean;
 | 
				
			||||||
  accelerateCtaType: 'alert' | 'button' = 'button';
 | 
					  accelerateCtaType: 'alert' | 'button' = 'button';
 | 
				
			||||||
  acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR && this.stateService.network === '';
 | 
					  acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR_BUTTON && this.stateService.network === '';
 | 
				
			||||||
  eligibleForAcceleration: boolean = false;
 | 
					  eligibleForAcceleration: boolean = false;
 | 
				
			||||||
  forceAccelerationSummary = false;
 | 
					  forceAccelerationSummary = false;
 | 
				
			||||||
  hideAccelerationSummary = false;
 | 
					  hideAccelerationSummary = false;
 | 
				
			||||||
@ -195,7 +200,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
    this.stateService.networkChanged$.subscribe(
 | 
					    this.stateService.networkChanged$.subscribe(
 | 
				
			||||||
      (network) => {
 | 
					      (network) => {
 | 
				
			||||||
        this.network = network;
 | 
					        this.network = network;
 | 
				
			||||||
        this.acceleratorAvailable = this.stateService.env.ACCELERATOR && this.stateService.network === '';
 | 
					        this.acceleratorAvailable = this.stateService.env.ACCELERATOR_BUTTON && this.stateService.network === '';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -225,6 +230,25 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
      this.latestBlock = blocks[0];
 | 
					      this.latestBlock = blocks[0];
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.transactionTimesSubscription = this.transactionTimes$.pipe(
 | 
				
			||||||
 | 
					      tap(() => {
 | 
				
			||||||
 | 
					        this.isLoadingFirstSeen = true;
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					      switchMap((txid) => this.apiService.getTransactionTimes$([txid]).pipe(
 | 
				
			||||||
 | 
					        retry({ count: 2, delay: 2000 }),
 | 
				
			||||||
 | 
					        // Try again until we either get a valid response, or the transaction is confirmed
 | 
				
			||||||
 | 
					        repeat({ delay: 2000 }),
 | 
				
			||||||
 | 
					        filter((transactionTimes) => transactionTimes?.length && transactionTimes[0] > 0 && !this.tx.status?.confirmed),
 | 
				
			||||||
 | 
					        take(1),
 | 
				
			||||||
 | 
					      )),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .subscribe((transactionTimes) => {
 | 
				
			||||||
 | 
					      this.isLoadingFirstSeen = false;
 | 
				
			||||||
 | 
					      if (transactionTimes?.length && transactionTimes[0]) {
 | 
				
			||||||
 | 
					        this.transactionTime = transactionTimes[0];
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.fetchCpfpSubscription = this.fetchCpfp$
 | 
					    this.fetchCpfpSubscription = this.fetchCpfp$
 | 
				
			||||||
      .pipe(
 | 
					      .pipe(
 | 
				
			||||||
        switchMap((txId) =>
 | 
					        switchMap((txId) =>
 | 
				
			||||||
@ -572,7 +596,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
            if (tx.firstSeen) {
 | 
					            if (tx.firstSeen) {
 | 
				
			||||||
              this.transactionTime = tx.firstSeen;
 | 
					              this.transactionTime = tx.firstSeen;
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              this.getTransactionTime();
 | 
					              this.transactionTimes$.next(tx.txid);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            this.fetchAcceleration$.next(tx.status.block_height);
 | 
					            this.fetchAcceleration$.next(tx.status.block_height);
 | 
				
			||||||
@ -625,7 +649,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.stateService.txConfirmed$.subscribe(([txConfirmed, block]) => {
 | 
					    this.txConfirmedSubscription = this.stateService.txConfirmed$.subscribe(([txConfirmed, block]) => {
 | 
				
			||||||
      if (txConfirmed && this.tx && !this.tx.status.confirmed && txConfirmed === this.tx.txid) {
 | 
					      if (txConfirmed && this.tx && !this.tx.status.confirmed && txConfirmed === this.tx.txid) {
 | 
				
			||||||
        if (this.tx.acceleration) {
 | 
					        if (this.tx.acceleration) {
 | 
				
			||||||
          this.waitingForAccelerationInfo = true;
 | 
					          this.waitingForAccelerationInfo = true;
 | 
				
			||||||
@ -729,7 +753,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
          this.accelerationPositions,
 | 
					          this.accelerationPositions,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    )
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngAfterViewInit(): void {
 | 
					  ngAfterViewInit(): void {
 | 
				
			||||||
@ -763,28 +787,6 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
    return of(false);
 | 
					    return of(false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getTransactionTime() {
 | 
					 | 
				
			||||||
    this.isLoadingFirstSeen = true;
 | 
					 | 
				
			||||||
    this.apiService
 | 
					 | 
				
			||||||
      .getTransactionTimes$([this.tx.txid])
 | 
					 | 
				
			||||||
      .pipe(
 | 
					 | 
				
			||||||
        retry({ count: 2, delay: 2000 }),
 | 
					 | 
				
			||||||
        catchError(() => {
 | 
					 | 
				
			||||||
          this.isLoadingFirstSeen = false;
 | 
					 | 
				
			||||||
          return throwError(() => new Error(''));
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
      .subscribe((transactionTimes) => {
 | 
					 | 
				
			||||||
        if (transactionTimes?.length && transactionTimes[0]) {
 | 
					 | 
				
			||||||
          this.transactionTime = transactionTimes[0];
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          setTimeout(() => {
 | 
					 | 
				
			||||||
            this.getTransactionTime();
 | 
					 | 
				
			||||||
          }, 2000);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  setCpfpInfo(cpfpInfo: CpfpInfo): void {
 | 
					  setCpfpInfo(cpfpInfo: CpfpInfo): void {
 | 
				
			||||||
    if (!cpfpInfo || !this.tx) {
 | 
					    if (!cpfpInfo || !this.tx) {
 | 
				
			||||||
      this.cpfpInfo = null;
 | 
					      this.cpfpInfo = null;
 | 
				
			||||||
@ -1057,6 +1059,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
  ngOnDestroy() {
 | 
					  ngOnDestroy() {
 | 
				
			||||||
    this.subscription.unsubscribe();
 | 
					    this.subscription.unsubscribe();
 | 
				
			||||||
    this.fetchCpfpSubscription.unsubscribe();
 | 
					    this.fetchCpfpSubscription.unsubscribe();
 | 
				
			||||||
 | 
					    this.transactionTimesSubscription.unsubscribe();
 | 
				
			||||||
    this.fetchRbfSubscription.unsubscribe();
 | 
					    this.fetchRbfSubscription.unsubscribe();
 | 
				
			||||||
    this.fetchCachedTxSubscription.unsubscribe();
 | 
					    this.fetchCachedTxSubscription.unsubscribe();
 | 
				
			||||||
    this.fetchAccelerationSubscription.unsubscribe();
 | 
					    this.fetchAccelerationSubscription.unsubscribe();
 | 
				
			||||||
@ -1070,6 +1073,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
 | 
				
			|||||||
    this.blocksSubscription.unsubscribe();
 | 
					    this.blocksSubscription.unsubscribe();
 | 
				
			||||||
    this.miningSubscription?.unsubscribe();
 | 
					    this.miningSubscription?.unsubscribe();
 | 
				
			||||||
    this.auditSubscription?.unsubscribe();
 | 
					    this.auditSubscription?.unsubscribe();
 | 
				
			||||||
 | 
					    this.txConfirmedSubscription?.unsubscribe();
 | 
				
			||||||
    this.currencyChangeSubscription?.unsubscribe();
 | 
					    this.currencyChangeSubscription?.unsubscribe();
 | 
				
			||||||
    this.leaveTransaction();
 | 
					    this.leaveTransaction();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -8993,7 +8993,7 @@ export const restApiDocsData = [
 | 
				
			|||||||
    fragment: "accelerator-estimate",
 | 
					    fragment: "accelerator-estimate",
 | 
				
			||||||
    title: "POST Calculate Estimated Costs",
 | 
					    title: "POST Calculate Estimated Costs",
 | 
				
			||||||
    description: {
 | 
					    description: {
 | 
				
			||||||
      default: "<p>Returns estimated costs to accelerate a transaction. Optionally set the <code>api_key</code> header to get customized estimation.</p>"
 | 
					      default: "<p>Returns estimated costs to accelerate a transaction. Optionally set the <code>X-Mempool-Auth</code> header to get customized estimation.</p>"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    urlString: "/v1/services/accelerator/estimate",
 | 
					    urlString: "/v1/services/accelerator/estimate",
 | 
				
			||||||
    showConditions: [""],
 | 
					    showConditions: [""],
 | 
				
			||||||
@ -9009,7 +9009,7 @@ export const restApiDocsData = [
 | 
				
			|||||||
          esModule: [],
 | 
					          esModule: [],
 | 
				
			||||||
          commonJS: [],
 | 
					          commonJS: [],
 | 
				
			||||||
          curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29"],
 | 
					          curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29"],
 | 
				
			||||||
          headers: "api_key: stacksats",
 | 
					          headers: "X-Mempool-Auth: stacksats",
 | 
				
			||||||
          response: `{
 | 
					          response: `{
 | 
				
			||||||
  "txSummary": {
 | 
					  "txSummary": {
 | 
				
			||||||
    "txid": "ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29",
 | 
					    "txid": "ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29",
 | 
				
			||||||
@ -9240,7 +9240,7 @@ export const restApiDocsData = [
 | 
				
			|||||||
          esModule: [],
 | 
					          esModule: [],
 | 
				
			||||||
          commonJS: [],
 | 
					          commonJS: [],
 | 
				
			||||||
          curl: [],
 | 
					          curl: [],
 | 
				
			||||||
          headers: "api_key: stacksats",
 | 
					          headers: "X-Mempool-Auth: stacksats",
 | 
				
			||||||
          response: `[
 | 
					          response: `[
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "type": "Bitcoin",
 | 
					    "type": "Bitcoin",
 | 
				
			||||||
@ -9288,7 +9288,7 @@ export const restApiDocsData = [
 | 
				
			|||||||
          esModule: [],
 | 
					          esModule: [],
 | 
				
			||||||
          commonJS: [],
 | 
					          commonJS: [],
 | 
				
			||||||
          curl: [],
 | 
					          curl: [],
 | 
				
			||||||
          headers: "api_key: stacksats",
 | 
					          headers: "X-Mempool-Auth: stacksats",
 | 
				
			||||||
          response: `{
 | 
					          response: `{
 | 
				
			||||||
  "balance": 99900000,
 | 
					  "balance": 99900000,
 | 
				
			||||||
  "hold": 101829,
 | 
					  "hold": 101829,
 | 
				
			||||||
@ -9322,7 +9322,7 @@ export const restApiDocsData = [
 | 
				
			|||||||
          esModule: [],
 | 
					          esModule: [],
 | 
				
			||||||
          commonJS: [],
 | 
					          commonJS: [],
 | 
				
			||||||
          curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&userBid=21000000"],
 | 
					          curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&userBid=21000000"],
 | 
				
			||||||
          headers: "api_key: stacksats",
 | 
					          headers: "X-Mempool-Auth: stacksats",
 | 
				
			||||||
          response: `HTTP/1.1 200 OK`,
 | 
					          response: `HTTP/1.1 200 OK`,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -9352,7 +9352,7 @@ export const restApiDocsData = [
 | 
				
			|||||||
          esModule: [],
 | 
					          esModule: [],
 | 
				
			||||||
          commonJS: [],
 | 
					          commonJS: [],
 | 
				
			||||||
          curl: [],
 | 
					          curl: [],
 | 
				
			||||||
          headers: "api_key: stacksats",
 | 
					          headers: "X-Mempool-Auth: stacksats",
 | 
				
			||||||
          response: `[
 | 
					          response: `[
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "id": 89,
 | 
					    "id": 89,
 | 
				
			||||||
 | 
				
			|||||||
@ -408,6 +408,7 @@ export interface Acceleration {
 | 
				
			|||||||
  bidBoost?: number;
 | 
					  bidBoost?: number;
 | 
				
			||||||
  boostCost?: number;
 | 
					  boostCost?: number;
 | 
				
			||||||
  boostRate?: number;
 | 
					  boostRate?: number;
 | 
				
			||||||
 | 
					  minedByPoolUniqueId?: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface AccelerationHistoryParams {
 | 
					export interface AccelerationHistoryParams {
 | 
				
			||||||
 | 
				
			|||||||
@ -536,6 +536,10 @@ export class ApiService {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logAccelerationRequest$(txid: string): Observable<any> {
 | 
				
			||||||
 | 
					    return this.httpClient.post(this.apiBaseUrl + this.apiBasePath + '/api/v1/acceleration/request/' + txid, '');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Cache methods
 | 
					  // Cache methods
 | 
				
			||||||
  async setBlockAuditLoaded(hash: string) {
 | 
					  async setBlockAuditLoaded(hash: string) {
 | 
				
			||||||
    this.blockAuditLoaded[hash] = true;
 | 
					    this.blockAuditLoaded[hash] = true;
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@ export class EnterpriseService {
 | 
				
			|||||||
      this.fetchSubdomainInfo();
 | 
					      this.fetchSubdomainInfo();
 | 
				
			||||||
      this.disableSubnetworks();
 | 
					      this.disableSubnetworks();
 | 
				
			||||||
      this.stateService.env.ACCELERATOR = false;
 | 
					      this.stateService.env.ACCELERATOR = false;
 | 
				
			||||||
 | 
					      this.stateService.env.ACCELERATOR_BUTTON = false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      this.insertMatomo();
 | 
					      this.insertMatomo();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -137,6 +137,10 @@ export class ServicesApiServices {
 | 
				
			|||||||
    return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/cashapp`, { txInput: txInput, token: token, cashtag: cashtag, referenceId: referenceId, accelerationUUID: accelerationUUID });
 | 
					    return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/cashapp`, { txInput: txInput, token: token, cashtag: cashtag, referenceId: referenceId, accelerationUUID: accelerationUUID });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  accelerateWithApplePay$(txInput: string, token: string, cardTag: string, referenceId: string, accelerationUUID: string) {
 | 
				
			||||||
 | 
					    return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate/applePay`, { txInput: txInput, cardTag: cardTag, token: token, referenceId: referenceId, accelerationUUID: accelerationUUID });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getAccelerations$(): Observable<Acceleration[]> {
 | 
					  getAccelerations$(): Observable<Acceleration[]> {
 | 
				
			||||||
    return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`);
 | 
					    return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -71,6 +71,7 @@ export interface Env {
 | 
				
			|||||||
  SIGNET_BLOCK_AUDIT_START_HEIGHT: number;
 | 
					  SIGNET_BLOCK_AUDIT_START_HEIGHT: number;
 | 
				
			||||||
  HISTORICAL_PRICE: boolean;
 | 
					  HISTORICAL_PRICE: boolean;
 | 
				
			||||||
  ACCELERATOR: boolean;
 | 
					  ACCELERATOR: boolean;
 | 
				
			||||||
 | 
					  ACCELERATOR_BUTTON: boolean;
 | 
				
			||||||
  PUBLIC_ACCELERATIONS: boolean;
 | 
					  PUBLIC_ACCELERATIONS: boolean;
 | 
				
			||||||
  ADDITIONAL_CURRENCIES: boolean;
 | 
					  ADDITIONAL_CURRENCIES: boolean;
 | 
				
			||||||
  GIT_COMMIT_HASH_MEMPOOL_SPACE?: string;
 | 
					  GIT_COMMIT_HASH_MEMPOOL_SPACE?: string;
 | 
				
			||||||
@ -108,6 +109,7 @@ const defaultEnv: Env = {
 | 
				
			|||||||
  'SIGNET_BLOCK_AUDIT_START_HEIGHT': 0,
 | 
					  'SIGNET_BLOCK_AUDIT_START_HEIGHT': 0,
 | 
				
			||||||
  'HISTORICAL_PRICE': true,
 | 
					  'HISTORICAL_PRICE': true,
 | 
				
			||||||
  'ACCELERATOR': false,
 | 
					  'ACCELERATOR': false,
 | 
				
			||||||
 | 
					  'ACCELERATOR_BUTTON': true,
 | 
				
			||||||
  'PUBLIC_ACCELERATIONS': false,
 | 
					  'PUBLIC_ACCELERATIONS': false,
 | 
				
			||||||
  'ADDITIONAL_CURRENCIES': false,
 | 
					  'ADDITIONAL_CURRENCIES': false,
 | 
				
			||||||
  'SERVICES_API': 'https://mempool.space/api/v1/services',
 | 
					  'SERVICES_API': 'https://mempool.space/api/v1/services',
 | 
				
			||||||
 | 
				
			|||||||
@ -195,3 +195,47 @@ export function insecureRandomUUID(): string {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  return uuid.slice(0, -1);
 | 
					  return uuid.slice(0, -1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://stackoverflow.com/a/60467595
 | 
				
			||||||
 | 
					export function md5(inputString): string {
 | 
				
			||||||
 | 
					    var hc="0123456789abcdef";
 | 
				
			||||||
 | 
					    function rh(n) {var j,s="";for(j=0;j<=3;j++) s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);return s;}
 | 
				
			||||||
 | 
					    function ad(x,y) {var l=(x&0xFFFF)+(y&0xFFFF);var m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);}
 | 
				
			||||||
 | 
					    function rl(n,c)            {return (n<<c)|(n>>>(32-c));}
 | 
				
			||||||
 | 
					    function cm(q,a,b,x,s,t)    {return ad(rl(ad(ad(a,q),ad(x,t)),s),b);}
 | 
				
			||||||
 | 
					    function ff(a,b,c,d,x,s,t)  {return cm((b&c)|((~b)&d),a,b,x,s,t);}
 | 
				
			||||||
 | 
					    function gg(a,b,c,d,x,s,t)  {return cm((b&d)|(c&(~d)),a,b,x,s,t);}
 | 
				
			||||||
 | 
					    function hh(a,b,c,d,x,s,t)  {return cm(b^c^d,a,b,x,s,t);}
 | 
				
			||||||
 | 
					    function ii(a,b,c,d,x,s,t)  {return cm(c^(b|(~d)),a,b,x,s,t);}
 | 
				
			||||||
 | 
					    function sb(x) {
 | 
				
			||||||
 | 
					        var i;var nblk=((x.length+8)>>6)+1;var blks=new Array(nblk*16);for(i=0;i<nblk*16;i++) blks[i]=0;
 | 
				
			||||||
 | 
					        for(i=0;i<x.length;i++) blks[i>>2]|=x.charCodeAt(i)<<((i%4)*8);
 | 
				
			||||||
 | 
					        blks[i>>2]|=0x80<<((i%4)*8);blks[nblk*16-2]=x.length*8;return blks;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var i,x=sb(""+inputString),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd;
 | 
				
			||||||
 | 
					    for(i=0;i<x.length;i+=16) {olda=a;oldb=b;oldc=c;oldd=d;
 | 
				
			||||||
 | 
					        a=ff(a,b,c,d,x[i+ 0], 7, -680876936);d=ff(d,a,b,c,x[i+ 1],12, -389564586);c=ff(c,d,a,b,x[i+ 2],17,  606105819);
 | 
				
			||||||
 | 
					        b=ff(b,c,d,a,x[i+ 3],22,-1044525330);a=ff(a,b,c,d,x[i+ 4], 7, -176418897);d=ff(d,a,b,c,x[i+ 5],12, 1200080426);
 | 
				
			||||||
 | 
					        c=ff(c,d,a,b,x[i+ 6],17,-1473231341);b=ff(b,c,d,a,x[i+ 7],22,  -45705983);a=ff(a,b,c,d,x[i+ 8], 7, 1770035416);
 | 
				
			||||||
 | 
					        d=ff(d,a,b,c,x[i+ 9],12,-1958414417);c=ff(c,d,a,b,x[i+10],17,     -42063);b=ff(b,c,d,a,x[i+11],22,-1990404162);
 | 
				
			||||||
 | 
					        a=ff(a,b,c,d,x[i+12], 7, 1804603682);d=ff(d,a,b,c,x[i+13],12,  -40341101);c=ff(c,d,a,b,x[i+14],17,-1502002290);
 | 
				
			||||||
 | 
					        b=ff(b,c,d,a,x[i+15],22, 1236535329);a=gg(a,b,c,d,x[i+ 1], 5, -165796510);d=gg(d,a,b,c,x[i+ 6], 9,-1069501632);
 | 
				
			||||||
 | 
					        c=gg(c,d,a,b,x[i+11],14,  643717713);b=gg(b,c,d,a,x[i+ 0],20, -373897302);a=gg(a,b,c,d,x[i+ 5], 5, -701558691);
 | 
				
			||||||
 | 
					        d=gg(d,a,b,c,x[i+10], 9,   38016083);c=gg(c,d,a,b,x[i+15],14, -660478335);b=gg(b,c,d,a,x[i+ 4],20, -405537848);
 | 
				
			||||||
 | 
					        a=gg(a,b,c,d,x[i+ 9], 5,  568446438);d=gg(d,a,b,c,x[i+14], 9,-1019803690);c=gg(c,d,a,b,x[i+ 3],14, -187363961);
 | 
				
			||||||
 | 
					        b=gg(b,c,d,a,x[i+ 8],20, 1163531501);a=gg(a,b,c,d,x[i+13], 5,-1444681467);d=gg(d,a,b,c,x[i+ 2], 9,  -51403784);
 | 
				
			||||||
 | 
					        c=gg(c,d,a,b,x[i+ 7],14, 1735328473);b=gg(b,c,d,a,x[i+12],20,-1926607734);a=hh(a,b,c,d,x[i+ 5], 4,    -378558);
 | 
				
			||||||
 | 
					        d=hh(d,a,b,c,x[i+ 8],11,-2022574463);c=hh(c,d,a,b,x[i+11],16, 1839030562);b=hh(b,c,d,a,x[i+14],23,  -35309556);
 | 
				
			||||||
 | 
					        a=hh(a,b,c,d,x[i+ 1], 4,-1530992060);d=hh(d,a,b,c,x[i+ 4],11, 1272893353);c=hh(c,d,a,b,x[i+ 7],16, -155497632);
 | 
				
			||||||
 | 
					        b=hh(b,c,d,a,x[i+10],23,-1094730640);a=hh(a,b,c,d,x[i+13], 4,  681279174);d=hh(d,a,b,c,x[i+ 0],11, -358537222);
 | 
				
			||||||
 | 
					        c=hh(c,d,a,b,x[i+ 3],16, -722521979);b=hh(b,c,d,a,x[i+ 6],23,   76029189);a=hh(a,b,c,d,x[i+ 9], 4, -640364487);
 | 
				
			||||||
 | 
					        d=hh(d,a,b,c,x[i+12],11, -421815835);c=hh(c,d,a,b,x[i+15],16,  530742520);b=hh(b,c,d,a,x[i+ 2],23, -995338651);
 | 
				
			||||||
 | 
					        a=ii(a,b,c,d,x[i+ 0], 6, -198630844);d=ii(d,a,b,c,x[i+ 7],10, 1126891415);c=ii(c,d,a,b,x[i+14],15,-1416354905);
 | 
				
			||||||
 | 
					        b=ii(b,c,d,a,x[i+ 5],21,  -57434055);a=ii(a,b,c,d,x[i+12], 6, 1700485571);d=ii(d,a,b,c,x[i+ 3],10,-1894986606);
 | 
				
			||||||
 | 
					        c=ii(c,d,a,b,x[i+10],15,   -1051523);b=ii(b,c,d,a,x[i+ 1],21,-2054922799);a=ii(a,b,c,d,x[i+ 8], 6, 1873313359);
 | 
				
			||||||
 | 
					        d=ii(d,a,b,c,x[i+15],10,  -30611744);c=ii(c,d,a,b,x[i+ 6],15,-1560198380);b=ii(b,c,d,a,x[i+13],21, 1309151649);
 | 
				
			||||||
 | 
					        a=ii(a,b,c,d,x[i+ 4], 6, -145523070);d=ii(d,a,b,c,x[i+11],10,-1120210379);c=ii(c,d,a,b,x[i+ 2],15,  718787259);
 | 
				
			||||||
 | 
					        b=ii(b,c,d,a,x[i+ 9],21, -343485551);a=ad(a,olda);b=ad(b,oldb);c=ad(c,oldc);d=ad(d,oldd);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return rh(a)+rh(b)+rh(c)+rh(d);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1520,6 +1520,10 @@
 | 
				
			|||||||
          <context context-type="sourcefile">src/app/components/acceleration/accelerations-list/accelerations-list.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/acceleration/accelerations-list/accelerations-list.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">53</context>
 | 
					          <context context-type="linenumber">53</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
 | 
					        <context-group purpose="location">
 | 
				
			||||||
 | 
					          <context context-type="sourcefile">src/app/components/address/address.component.html</context>
 | 
				
			||||||
 | 
					          <context context-type="linenumber">252</context>
 | 
				
			||||||
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/tracker/tracker-bar.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/tracker/tracker-bar.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">4</context>
 | 
					          <context context-type="linenumber">4</context>
 | 
				
			||||||
@ -2042,14 +2046,6 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <note priority="1" from="description">address.confirmed-balance</note>
 | 
					        <note priority="1" from="description">address.confirmed-balance</note>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="8211b4be0291a035cd67aeb84782c9e87d4daca3" datatype="html">
 | 
					 | 
				
			||||||
        <source>Unconfirmed balance</source>
 | 
					 | 
				
			||||||
        <context-group purpose="location">
 | 
					 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/address/address.component.html</context>
 | 
					 | 
				
			||||||
          <context context-type="linenumber">252</context>
 | 
					 | 
				
			||||||
        </context-group>
 | 
					 | 
				
			||||||
        <note priority="1" from="description">address.unconfirmed-balance</note>
 | 
					 | 
				
			||||||
      </trans-unit>
 | 
					 | 
				
			||||||
      <trans-unit id="c7daf1b7c126095c054f2d3728ae790b0ceef33a" datatype="html">
 | 
					      <trans-unit id="c7daf1b7c126095c054f2d3728ae790b0ceef33a" datatype="html">
 | 
				
			||||||
        <source>Confirmed UTXOs</source>
 | 
					        <source>Confirmed UTXOs</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
@ -2058,13 +2054,13 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <note priority="1" from="description">address.confirmed-utxos</note>
 | 
					        <note priority="1" from="description">address.confirmed-utxos</note>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="928915f31e05788ae07a353761e10e5992b2b58c" datatype="html">
 | 
					      <trans-unit id="ba986bd9e2848d2ef7329394ec87b7f4eaf61118" datatype="html">
 | 
				
			||||||
        <source>Unconfirmed UTXOs</source>
 | 
					        <source>Pending UTXOs</source>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/address/address.component.html</context>
 | 
					          <context context-type="sourcefile">src/app/components/address/address.component.html</context>
 | 
				
			||||||
          <context context-type="linenumber">262</context>
 | 
					          <context context-type="linenumber">262</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <note priority="1" from="description">address.unconfirmed-utxos</note>
 | 
					        <note priority="1" from="description">address.pending-utxos</note>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="f61c6867295f3b53d23557021f2f4e0aa1d0b8fc" datatype="html">
 | 
					      <trans-unit id="f61c6867295f3b53d23557021f2f4e0aa1d0b8fc" datatype="html">
 | 
				
			||||||
        <source>Type</source>
 | 
					        <source>Type</source>
 | 
				
			||||||
@ -6640,7 +6636,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/transaction/transaction.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/transaction/transaction.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">498</context>
 | 
					          <context context-type="linenumber">499</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="meta.description.bitcoin.transaction" datatype="html">
 | 
					      <trans-unit id="meta.description.bitcoin.transaction" datatype="html">
 | 
				
			||||||
@ -6655,7 +6651,7 @@
 | 
				
			|||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
        <context-group purpose="location">
 | 
					        <context-group purpose="location">
 | 
				
			||||||
          <context context-type="sourcefile">src/app/components/transaction/transaction.component.ts</context>
 | 
					          <context context-type="sourcefile">src/app/components/transaction/transaction.component.ts</context>
 | 
				
			||||||
          <context context-type="linenumber">502</context>
 | 
					          <context context-type="linenumber">503</context>
 | 
				
			||||||
        </context-group>
 | 
					        </context-group>
 | 
				
			||||||
      </trans-unit>
 | 
					      </trans-unit>
 | 
				
			||||||
      <trans-unit id="7e06b8dd9f29261827018351cd71efe1c87839de" datatype="html">
 | 
					      <trans-unit id="7e06b8dd9f29261827018351cd71efe1c87839de" datatype="html">
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										84
									
								
								frontend/src/resources/apple-pay.svg
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										84
									
								
								frontend/src/resources/apple-pay.svg
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,84 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="utf-8"?>
 | 
				
			||||||
 | 
					<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
				
			||||||
 | 
					<svg version="1.1" id="Artwork" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
				
			||||||
 | 
						 width="165.52107px" height="105.9651px" viewBox="0 0 165.52107 105.9651" enable-background="new 0 0 165.52107 105.9651"
 | 
				
			||||||
 | 
						 xml:space="preserve">
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
						<path id="XMLID_4_" d="M150.69807,0H14.82318c-0.5659,0-1.1328,0-1.69769,0.0033c-0.47751,0.0034-0.95391,0.0087-1.43031,0.0217
 | 
				
			||||||
 | 
							c-1.039,0.0281-2.0869,0.0894-3.1129,0.2738c-1.0424,0.1876-2.0124,0.4936-2.9587,0.9754
 | 
				
			||||||
 | 
							c-0.9303,0.4731-1.782,1.0919-2.52009,1.8303c-0.73841,0.7384-1.35721,1.5887-1.83021,2.52
 | 
				
			||||||
 | 
							c-0.4819,0.9463-0.7881,1.9166-0.9744,2.9598c-0.18539,1.0263-0.2471,2.074-0.2751,3.1119
 | 
				
			||||||
 | 
							c-0.0128,0.4764-0.01829,0.9528-0.0214,1.4291c-0.0033,0.5661-0.0022,1.1318-0.0022,1.6989V91.142
 | 
				
			||||||
 | 
							c0,0.5671-0.0011,1.13181,0.0022,1.69901c0.00311,0.4763,0.0086,0.9527,0.0214,1.4291
 | 
				
			||||||
 | 
							c0.028,1.03699,0.08971,2.08469,0.2751,3.11069c0.1863,1.0436,0.4925,2.0135,0.9744,2.9599
 | 
				
			||||||
 | 
							c0.473,0.9313,1.0918,1.7827,1.83021,2.52c0.73809,0.7396,1.58979,1.3583,2.52009,1.8302
 | 
				
			||||||
 | 
							c0.9463,0.4831,1.9163,0.7892,2.9587,0.9767c1.026,0.1832,2.0739,0.2456,3.1129,0.2737c0.4764,0.0108,0.9528,0.0172,1.43031,0.0194
 | 
				
			||||||
 | 
							c0.56489,0.0044,1.13179,0.0044,1.69769,0.0044h135.87489c0.5649,0,1.13181,0,1.69659-0.0044
 | 
				
			||||||
 | 
							c0.47641-0.0022,0.95282-0.0086,1.4314-0.0194c1.0368-0.0281,2.0845-0.0905,3.11301-0.2737
 | 
				
			||||||
 | 
							c1.041-0.1875,2.0112-0.4936,2.9576-0.9767c0.9313-0.4719,1.7805-1.0906,2.52011-1.8302c0.7372-0.7373,1.35599-1.5887,1.8302-2.52
 | 
				
			||||||
 | 
							c0.48299-0.9464,0.78889-1.9163,0.97429-2.9599c0.1855-1.026,0.2457-2.0737,0.2738-3.11069
 | 
				
			||||||
 | 
							c0.013-0.4764,0.01941-0.9528,0.02161-1.4291c0.00439-0.5672,0.00439-1.1319,0.00439-1.69901V14.8242
 | 
				
			||||||
 | 
							c0-0.5671,0-1.1328-0.00439-1.6989c-0.0022-0.4763-0.00861-0.9527-0.02161-1.4291c-0.02811-1.0379-0.0883-2.0856-0.2738-3.1119
 | 
				
			||||||
 | 
							c-0.18539-1.0432-0.4913-2.0135-0.97429-2.9598c-0.47421-0.9313-1.093-1.7816-1.8302-2.52
 | 
				
			||||||
 | 
							c-0.73961-0.7384-1.58881-1.3572-2.52011-1.8303c-0.9464-0.4818-1.9166-0.7878-2.9576-0.9754
 | 
				
			||||||
 | 
							c-1.0285-0.1844-2.0762-0.2457-3.11301-0.2738c-0.47858-0.013-0.95499-0.0183-1.4314-0.0217C151.82988,0,151.26297,0,150.69807,0
 | 
				
			||||||
 | 
							L150.69807,0z"/>
 | 
				
			||||||
 | 
						<path id="XMLID_3_" fill="#FFFFFF" d="M150.69807,3.532l1.67149,0.0032c0.4528,0.0032,0.90561,0.0081,1.36092,0.0205
 | 
				
			||||||
 | 
							c0.79201,0.0214,1.71849,0.0643,2.58209,0.2191c0.7507,0.1352,1.38029,0.3408,1.9845,0.6484
 | 
				
			||||||
 | 
							c0.5965,0.3031,1.14301,0.7003,1.62019,1.1768c0.479,0.4797,0.87671,1.0271,1.18381,1.6302
 | 
				
			||||||
 | 
							c0.30589,0.5995,0.51019,1.2261,0.64459,1.9823c0.1544,0.8542,0.1971,1.7832,0.21881,2.5801
 | 
				
			||||||
 | 
							c0.01219,0.4498,0.01819,0.8996,0.0204,1.3601c0.00429,0.5569,0.0042,1.1135,0.0042,1.6715V91.142
 | 
				
			||||||
 | 
							c0,0.558,0.00009,1.1136-0.0043,1.6824c-0.00211,0.4497-0.0081,0.8995-0.0204,1.3501c-0.02161,0.7957-0.0643,1.7242-0.2206,2.5885
 | 
				
			||||||
 | 
							c-0.13251,0.7458-0.3367,1.3725-0.64429,1.975c-0.30621,0.6016-0.70331,1.1484-1.18022,1.6251
 | 
				
			||||||
 | 
							c-0.47989,0.48-1.0246,0.876-1.62819,1.1819c-0.5997,0.3061-1.22821,0.51151-1.97151,0.6453
 | 
				
			||||||
 | 
							c-0.88109,0.157-1.84639,0.2002-2.57339,0.2199c-0.4574,0.0103-0.9126,0.01649-1.37889,0.0187
 | 
				
			||||||
 | 
							c-0.55571,0.0043-1.1134,0.0042-1.6692,0.0042H14.82318c-0.0074,0-0.0146,0-0.0221,0c-0.5494,0-1.0999,0-1.6593-0.0043
 | 
				
			||||||
 | 
							c-0.4561-0.00211-0.9112-0.0082-1.3512-0.0182c-0.7436-0.0201-1.7095-0.0632-2.5834-0.2193
 | 
				
			||||||
 | 
							c-0.74969-0.1348-1.3782-0.3402-1.9858-0.6503c-0.59789-0.3032-1.1422-0.6988-1.6223-1.1797
 | 
				
			||||||
 | 
							c-0.4764-0.4756-0.8723-1.0207-1.1784-1.6232c-0.3064-0.6019-0.5114-1.2305-0.64619-1.9852
 | 
				
			||||||
 | 
							c-0.15581-0.8626-0.19861-1.7874-0.22-2.5777c-0.01221-0.4525-0.01731-0.9049-0.02021-1.3547l-0.0022-1.3279l0.0001-0.3506V14.8242
 | 
				
			||||||
 | 
							l-0.0001-0.3506l0.0021-1.3251c0.003-0.4525,0.0081-0.9049,0.02031-1.357c0.02139-0.7911,0.06419-1.7163,0.22129-2.5861
 | 
				
			||||||
 | 
							c0.1336-0.7479,0.3385-1.3765,0.6465-1.9814c0.3037-0.5979,0.7003-1.1437,1.17921-1.6225
 | 
				
			||||||
 | 
							c0.477-0.4772,1.02309-0.8739,1.62479-1.1799c0.6011-0.3061,1.2308-0.5116,1.9805-0.6465c0.8638-0.1552,1.7909-0.198,2.5849-0.2195
 | 
				
			||||||
 | 
							c0.4526-0.0123,0.9052-0.0172,1.3544-0.0203l1.6771-0.0033H150.69807"/>
 | 
				
			||||||
 | 
						<g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<path d="M45.1862,35.64053c1.41724-1.77266,2.37897-4.15282,2.12532-6.58506c-2.07464,0.10316-4.60634,1.36871-6.07207,3.14276
 | 
				
			||||||
 | 
									c-1.31607,1.5192-2.4809,3.99902-2.17723,6.3293C41.39111,38.72954,43.71785,37.36345,45.1862,35.64053"/>
 | 
				
			||||||
 | 
								<path d="M47.28506,38.98252c-3.38211-0.20146-6.25773,1.91951-7.87286,1.91951c-1.61602,0-4.08931-1.81799-6.76438-1.76899
 | 
				
			||||||
 | 
									c-3.48177,0.05114-6.71245,2.01976-8.4793,5.15079c-3.63411,6.2636-0.95904,15.55471,2.57494,20.65606
 | 
				
			||||||
 | 
									c1.71618,2.5238,3.78447,5.30269,6.50976,5.20287c2.57494-0.10104,3.58421-1.66732,6.71416-1.66732
 | 
				
			||||||
 | 
									c3.12765,0,4.03679,1.66732,6.76252,1.61681c2.82665-0.05054,4.59381-2.52506,6.30997-5.05132
 | 
				
			||||||
 | 
									c1.96878-2.877,2.77473-5.65498,2.82542-5.80748c-0.0507-0.05051-5.45058-2.12204-5.50065-8.33358
 | 
				
			||||||
 | 
									c-0.05098-5.20101,4.23951-7.6749,4.44144-7.82832C52.3832,39.4881,48.5975,39.08404,47.28506,38.98252"/>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
							<g>
 | 
				
			||||||
 | 
								<path d="M76.73385,31.94381c7.35096,0,12.4697,5.06708,12.4697,12.44437c0,7.40363-5.22407,12.49704-12.65403,12.49704h-8.13892
 | 
				
			||||||
 | 
									v12.94318h-5.88037v-37.8846H76.73385z M68.41059,51.9493h6.74732c5.11975,0,8.0336-2.75636,8.0336-7.53479
 | 
				
			||||||
 | 
									c0-4.77792-2.91385-7.50845-8.00727-7.50845h-6.77365V51.9493z"/>
 | 
				
			||||||
 | 
								<path d="M90.73997,61.97864c0-4.8311,3.70182-7.79761,10.26583-8.16526l7.56061-0.44614v-2.12639
 | 
				
			||||||
 | 
									c0-3.07185-2.07423-4.90959-5.53905-4.90959c-3.28251,0-5.33041,1.57492-5.82871,4.04313h-5.35574
 | 
				
			||||||
 | 
									c0.31499-4.98859,4.56777-8.66407,11.3941-8.66407c6.69466,0,10.97377,3.54432,10.97377,9.08388v19.03421h-5.43472v-4.54194
 | 
				
			||||||
 | 
									h-0.13065c-1.60125,3.07185-5.09341,5.01441-8.71623,5.01441C94.52078,70.30088,90.73997,66.94038,90.73997,61.97864z
 | 
				
			||||||
 | 
									 M108.56641,59.4846v-2.17905l-6.8,0.41981c-3.38683,0.23649-5.30306,1.73291-5.30306,4.09579
 | 
				
			||||||
 | 
									c0,2.41504,1.99523,3.99046,5.04075,3.99046C105.46823,65.81161,108.56641,63.08108,108.56641,59.4846z"/>
 | 
				
			||||||
 | 
								<path d="M119.34167,79.9889v-4.5946c0.4193,0.10483,1.36425,0.10483,1.83723,0.10483c2.6252,0,4.04313-1.10245,4.90908-3.9378
 | 
				
			||||||
 | 
									c0-0.05267,0.49931-1.68025,0.49931-1.70658l-9.97616-27.64562h6.14268l6.98432,22.47371h0.10432l6.98433-22.47371h5.9857
 | 
				
			||||||
 | 
									l-10.34483,29.06304c-2.36186,6.69517-5.0924,8.84789-10.81577,8.84789C121.17891,80.12006,119.76098,80.06739,119.34167,79.9889
 | 
				
			||||||
 | 
									z"/>
 | 
				
			||||||
 | 
							</g>
 | 
				
			||||||
 | 
						</g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					<g>
 | 
				
			||||||
 | 
					</g>
 | 
				
			||||||
 | 
					</svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 6.2 KiB  | 
@ -13,6 +13,7 @@
 | 
				
			|||||||
  "ITEMS_PER_PAGE": 25,
 | 
					  "ITEMS_PER_PAGE": 25,
 | 
				
			||||||
  "LIGHTNING": true,
 | 
					  "LIGHTNING": true,
 | 
				
			||||||
  "ACCELERATOR": true,
 | 
					  "ACCELERATOR": true,
 | 
				
			||||||
 | 
					  "ACCELERATOR_BUTTON": true,
 | 
				
			||||||
  "PUBLIC_ACCELERATIONS": true,
 | 
					  "PUBLIC_ACCELERATIONS": true,
 | 
				
			||||||
  "AUDIT": true
 | 
					  "AUDIT": true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ heat()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
heatURLs=(
 | 
					heatURLs=(
 | 
				
			||||||
       '/api/v1/fees/recommended'
 | 
					       '/api/v1/fees/recommended'
 | 
				
			||||||
 | 
					       '/api/v1/accelerations'
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
while true
 | 
					while true
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,9 @@
 | 
				
			|||||||
# routing #
 | 
					# routing #
 | 
				
			||||||
###########
 | 
					###########
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					location /api/v1/accelerations {
 | 
				
			||||||
 | 
						try_files /dev/null @mempool-api-v1-services-cache-short;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
location /api/v1/assets {
 | 
					location /api/v1/assets {
 | 
				
			||||||
	try_files /dev/null @mempool-api-v1-services-cache-short;
 | 
						try_files /dev/null @mempool-api-v1-services-cache-short;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user