Compare commits

..
Author SHA1 Message Date
wiz 0a116804e8 Merge pull request #5347 from mempool/junderw/fix-docker-aarch64
Bump Rust version to 1.79
2024-07-18 15:08:22 +09:00
junderw 68edf4306c Bump Rust version to 1.79
Maintaining an old MSRV is not a priority for this project.
If you would like to keep an old MSRV active, please maintain your own patch/fork.
2024-07-18 01:07:05 +09:00
softsimon 61bbb95819 fix default docker unix socket path variable 2024-07-17 12:34:28 +08:00
softsimon 3fa32edf25 Merge pull request #5345 from mempool/dependabot/npm_and_yarn/frontend/fortawesome/fontawesome-common-types-6.6.0
Bump @fortawesome/fontawesome-common-types from 6.5.1 to 6.6.0 in /frontend
2024-07-17 11:48:05 +09:00
dependabot[bot] db220d9dfd Bump @fortawesome/fontawesome-common-types in /frontend
Bumps [@fortawesome/fontawesome-common-types](https://github.com/FortAwesome/Font-Awesome) from 6.5.1 to 6.6.0.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.5.1...6.6.0)

---
updated-dependencies:
- dependency-name: "@fortawesome/fontawesome-common-types"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-17 02:47:44 +00:00
softsimon bf61557879 Merge pull request #5344 from mempool/dependabot/npm_and_yarn/frontend/fortawesome/free-solid-svg-icons-6.6.0
Bump @fortawesome/free-solid-svg-icons from 6.5.1 to 6.6.0 in /frontend
2024-07-17 11:47:15 +09:00
dependabot[bot] ebaf5cd304 Bump @fortawesome/free-solid-svg-icons from 6.5.1 to 6.6.0 in /frontend
Bumps [@fortawesome/free-solid-svg-icons](https://github.com/FortAwesome/Font-Awesome) from 6.5.1 to 6.6.0.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.5.1...6.6.0)

---
updated-dependencies:
- dependency-name: "@fortawesome/free-solid-svg-icons"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-17 02:47:02 +00:00
softsimon 51154d3954 Merge pull request #5343 from mempool/dependabot/npm_and_yarn/frontend/fortawesome/fontawesome-svg-core-6.6.0
Bump @fortawesome/fontawesome-svg-core from 6.5.1 to 6.6.0 in /frontend
2024-07-17 11:46:09 +09:00
dependabot[bot] 41b4b2eddf Bump @fortawesome/fontawesome-svg-core from 6.5.1 to 6.6.0 in /frontend
Bumps [@fortawesome/fontawesome-svg-core](https://github.com/FortAwesome/Font-Awesome) from 6.5.1 to 6.6.0.
- [Release notes](https://github.com/FortAwesome/Font-Awesome/releases)
- [Changelog](https://github.com/FortAwesome/Font-Awesome/blob/6.x/CHANGELOG.md)
- [Commits](https://github.com/FortAwesome/Font-Awesome/compare/6.5.1...6.6.0)

---
updated-dependencies:
- dependency-name: "@fortawesome/fontawesome-svg-core"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-17 02:34:33 +00:00
softsimon 0dff7e82a3 Merge pull request #5341 from mempool/simon/retry-firstseen-onerror
retry firstseen on error
2024-07-15 02:03:20 +09:00
softsimon 9cba7ccf75 retry firstseen on error
fixes #5340
2024-07-14 20:44:34 +09:00
wiz 6177b97bd1 Merge pull request #5337 from mempool/nymkappa/invoice-check-http-code
[btcpay] handle new http code 204 when calling /payments/bitcoin/check
2024-07-14 20:12:23 +09:00
softsimon f7f1a99486 Merge pull request #5339 from mempool/mononaut/fix-pizza-status
fix pizza status
2024-07-14 17:22:53 +09:00
Mononaut 6b955acf9e [pizza] fix status icon layout w/ accelerator modal 2024-07-14 04:40:27 +00:00
Mononaut 530610add6 [pizza] fix trackerStage clobbered by ETA change 2024-07-14 04:39:46 +00:00
wiz 428f9369e2 Merge pull request #5338 from jlopp/jloppAgreement 2024-07-14 05:17:02 +09:00
softsimon a9defb21bb restore timeline lowercase time 2024-07-14 02:06:34 +09:00
nymkappa 680e9562a0 [btcpay] handle new http code 204 when calling /payments/bitcoin/check api 2024-07-13 21:07:13 +09:00
wiz 66c5c303b3 ops: Set HTTP CORS headers with caching in nginx for services 2024-07-13 20:20:15 +09:00
wiz 5a86c8c83a ops: Set HTTP CORS headers in nginx for services 2024-07-13 19:56:17 +09:00
softsimon 725e9c0d95 restore timeline lowercase time 2024-07-13 19:36:27 +09:00
softsimon 74e59d6ea5 Merge pull request #5333 from mempool/natsoni/timeline-updates
Acceleration timeline refactor
2024-07-13 18:53:39 +09:00
natsoni 9ac45a6cc3 Clear interval on destroy and remove commented code 2024-07-13 18:45:18 +09:00
wiz 94d537daa6 Merge pull request #5330 from mempool/simon/block-preview-miner-tag-design
Block preview new miner tag design
2024-07-13 18:37:45 +09:00
wiz 30bc026c28 Merge pull request #5331 from mempool/mononaut/accelerated-cpfp
show cpfp toggle on pending accelerations
2024-07-13 18:37:23 +09:00
wiz 21942f8ab1 Merge pull request #5334 from mempool/natsoni/click-on-acceleration-graph
Allow to click on bid boost graph to go on block page
2024-07-13 18:36:47 +09:00
wiz 147f55fec3 Merge pull request #5335 from mempool/natsoni/fix-btc-amount-pool
Fix btc amount in mining dashboard
2024-07-13 18:36:04 +09:00
natsoni e73f2cbdc1 Fix btc amount mining dashboard 2024-07-13 18:22:45 +09:00
softsimon 009e18b622 adjust lightning dashboard to be in line with new default dashboard 2024-07-13 18:18:56 +09:00
natsoni 5f20803e21 Allow to click on bid boost graph to go on block page 2024-07-13 18:16:41 +09:00
softsimon 832d16cf2d Merge pull request #5332 from hans-crypto/html-quickfix
Html quickfix
2024-07-13 17:38:10 +09:00
natsoni 5e8b5e75d8 Fix accelerated fee update logic 2024-07-13 17:31:49 +09:00
Hans ❤️ Crypto c5ef1011d8 Merge branch 'mempool:master' into html-quickfix 2024-07-13 10:23:28 +02:00
softsimon 6a14043641 Merge pull request #5094 from ordpool-space/hans-crypto-patch-1
Remove reference to bisq in unfurler
2024-07-13 17:09:21 +09:00
Mononaut 0f526f24cb show cpfp toggle on pending accelerations 2024-07-13 07:59:59 +00:00
softsimon 4426bb10a9 Block preview new miner tag design 2024-07-13 16:48:03 +09:00
natsoni 18a7859cca Merge branch 'master' into natsoni/timeline-updates 2024-07-13 16:25:14 +09:00
natsoni 349d491f7d Refactor timeline but keep times 2024-07-13 16:21:56 +09:00
wiz 7556424f0b Merge pull request #5328 from mempool/nymkappa/accel-dashboard-update
[accelerator] also show completed_provisional in accel dashboard
2024-07-13 16:03:16 +09:00
wiz 1d827a9724 Merge pull request #5329 from mempool/nymkappa/external-menu-link
[menu] link can be external
2024-07-13 16:01:10 +09:00
softsimon f019dd67b3 update i18n from transifex 2024-07-13 14:38:27 +09:00
Jameson Lopp 8b27ac1bbf add contributor agreement 2024-07-12 17:03:27 -04:00
nymkappa b91774d50c [menu] link can be external 2024-07-13 00:41:45 +09:00
nymkappa 22a5cd2de2 [accelerator] also show completed_provisional in accel dashboard 2024-07-12 23:45:41 +09:00
softsimon e5489277c6 i18n fixes 2024-07-12 23:20:18 +09:00
softsimon 04b6bee8a1 Merge pull request #5327 from mempool/revert-5321-natsoni/fees-on-acc-timeline
Revert "Show accelerated fee rates on timeline"
2024-07-12 19:10:17 +09:00
softsimon 6cd8cf660b Revert "Show accelerated fee rates on timeline" 2024-07-12 19:10:06 +09:00
wiz 1b6fd29c82 Merge pull request #5325 from mempool/mononaut/subnet-route-restrictions
Restrict accelerator routes to mainnet
2024-07-12 18:59:21 +09:00
softsimon a31dae67a8 Merge pull request #5326 from mempool/revert-5323-natsoni/timeline-feedback
Revert "Add accelerated word to timeline"
2024-07-12 18:58:20 +09:00
softsimon 76e3053207 Revert "Add accelerated word to timeline" 2024-07-12 18:58:02 +09:00
Mononaut 985b7577e4 Restrict accelerator routes to mainnet 2024-07-12 09:29:21 +00:00
wiz c748e5cda9 Merge pull request #5323 from mempool/natsoni/timeline-feedback 2024-07-12 18:12:27 +09:00
natsoni a99f45cd47 Add accelerated word to timeline 2024-07-12 18:00:02 +09:00
softsimon de1d7839b3 Merge pull request #5321 from mempool/natsoni/fees-on-acc-timeline
Show accelerated fee rates on timeline
2024-07-12 17:24:36 +09:00
natsoni 6aa3e38af2 Fix broken loader in accelerate fee rate line 2024-07-12 17:15:51 +09:00
softsimon dca7df709b Merge pull request #5305 from mempool/natsoni/avoid-fetching-full-audit
Avoid fetching full audit on tx page
2024-07-12 17:10:36 +09:00
softsimon e40e9f7d11 Merge pull request #5319 from mempool/orangesurf/accelerator-api
Update Accelerator API documentation
2024-07-12 17:04:28 +09:00
softsimon 285bb357ba Merge pull request #5317 from mempool/mononaut/coming-now
[accelerator] remove "coming soon" button state
2024-07-12 16:34:21 +09:00
natsoni c3b9828d42 Move block audit cache to apiService 2024-07-12 16:00:51 +09:00
softsimon 871e590305 Merge pull request #5322 from mempool/natsoni/fix-accelerations-graph
Fix accelerations graph view more
2024-07-12 15:08:59 +09:00
softsimon 0e5a1abb2b Merge pull request #5320 from mempool/mononaut/24h-acc-dash
Add 24h and all time views to accelerator dashboard
2024-07-12 15:02:46 +09:00
natsoni 5665c6e6ec Fix accelerations graph view more 2024-07-12 14:20:05 +09:00
natsoni 06b696f0bb Show fees rates on acceleration timeline 2024-07-12 01:58:20 +09:00
Mononaut 75ca963bd5 Add 24h and all time views to accelerator dashboard 2024-07-11 16:48:41 +00:00
orangesurf 3a6647eac0 Update Accelerator APIs 2024-07-11 18:12:23 +02:00
Mononaut 9ad6b925c8 [accelerator] remove "coming soon" button state 2024-07-11 12:27:31 +00:00
natsoni 17720b98c1 Avoid briefly displaying wrong accelerated fee rate on tx load 2024-07-11 20:38:38 +09:00
wiz 5bb3e930cc Merge pull request #5313 from mempool/mononaut/enable-cashapp
[accelerator] enable cashapp
2024-07-11 20:28:43 +09:00
wiz 347bddc974 Merge pull request #5315 from mempool/hunicus/faq-update-accelerate
Update faq
2024-07-11 20:28:16 +09:00
hunicus 4eca8240db Update accelerator faq mention for public availability 2024-07-11 18:18:13 +09:00
Mononaut 1c135b4c67 [accelerator] enable cashapp 2024-07-11 07:56:15 +00:00
softsimon f24223ca06 Merge pull request #5312 from mempool/mononaut/fix-enterprise-import
Fix broken enterpriseService import
2024-07-11 15:06:28 +09:00
Mononaut 9748aa05cf Fix broken enterpriseService import 2024-07-11 05:59:29 +00:00
wiz 1a5613bf65 Merge pull request #5311 from mempool/natsoni/accel-tx-fee-update
Update tx acceleration state on confirmation
2024-07-11 14:50:06 +09:00
wiz e55e4e378a Merge pull request #5310 from mempool/mononaut/acc-goal
accelerator goals
2024-07-11 01:21:15 +09:00
Mononaut 927eb98072 accelerator goals 2024-07-10 16:18:13 +00:00
natsoni 99ea1ad0a0 Avoid fetching full audit on tx page 2024-07-11 00:23:46 +09:00
softsimon fed3012449 prevent goggles from becoming small or move with many filters activated 2024-07-10 23:26:34 +09:00
natsoni bbff50527b Don't show Accelerated on tx just mined by non-participating pool 2024-07-10 23:23:40 +09:00
natsoni 4470461a98 Add retry logic to acceleration data fetching on tx page 2024-07-10 23:22:57 +09:00
natsoni 645fd98c30 Show actual accelerated fee rate on newly mined tracked tx 2024-07-10 23:21:53 +09:00
softsimon 10de603ee7 use default link color for top up link 2024-07-10 23:16:28 +09:00
softsimon 685c1c9fb2 Merge pull request #5308 from mempool/revert-5306-mononaut/selected-block-pool
Revert "align block arrows & reposition selected block pool tag"
2024-07-10 21:51:17 +09:00
softsimon d02a67766d Revert "align block arrows & reposition selected block pool tag" 2024-07-10 21:51:04 +09:00
wiz 7721fde7b6 Merge pull request #5306 from mempool/mononaut/selected-block-pool
align block arrows & reposition selected block pool tag
2024-07-10 21:33:02 +09:00
wiz aa10d1233c Merge pull request #5304 from mempool/natsoni/fix-miner-tag-loading
Possibly fix miner tag loading on tracked transactions
2024-07-10 21:31:56 +09:00
orangesurf ba79821aac 20240710 Update ToS and PP (#5307) 2024-07-10 21:29:02 +09:00
Mononaut e054e1d5a3 align block arrows & reposition selected block pool tag 2024-07-10 08:15:29 +00:00
softsimon 565910f9f9 Merge pull request #5303 from mempool/mononaut/oob-8dp
always show out-of-band block fees to 8 decimal places
2024-07-10 13:24:53 +09:00
natsoni 2915be8fd6 Possibly fix miner tag loading on tracked transactions 2024-07-10 12:55:34 +09:00
Mononaut ff25b8ff1e always show out-of-band block fees to 8 decimal places 2024-07-10 03:51:51 +00:00
softsimon 2d03ab6346 make arrow position more consistent
fixes #5180
2024-07-10 12:49:16 +09:00
wiz a530b70f9f Merge pull request #5302 from mempool/simon/smaller-block-arrow
Smaller block arrow
2024-07-10 01:46:42 +09:00
softsimon 986d71d47f Smaller block arrow 2024-07-10 01:44:15 +09:00
wiz 79f4720516 Merge pull request #5299 from mempool/mononaut/services-api-config
services api endpoint config
2024-07-09 23:51:53 +09:00
wiz 6135b1db10 Merge pull request #5300 from mempool/simon/pool-search-icons
Icons to pool search
2024-07-09 23:51:05 +09:00
wiz 4269077d4b Merge pull request #5301 from mempool/natsoni/hide-standard-eta-timeline
Remove standard ETA from timeline
2024-07-09 23:50:47 +09:00
natsoni da0df70ad2 Acc timeline: More similar color logic with RBF 2024-07-09 22:14:40 +09:00
softsimon 6253d3716d Icons to pool search 2024-07-09 21:52:19 +09:00
Mononaut 614432426a call services api directly, make endpoint configurable 2024-07-09 12:23:52 +00:00
softsimon e51951c3ff Merge pull request #5298 from svrgnty/master
add seconds to address and transaction views
2024-07-09 21:02:34 +09:00
natsoni b38bf0f7b6 Hide standard ETA data until proper ETA calculation gets implemented 2024-07-09 20:50:47 +09:00
svrgnty 503de93094 add seconds to address and transaction views 2024-07-09 13:10:48 +02:00
natsoni 58f3169712 Faster, synced chevron animation 2024-07-09 18:48:58 +09:00
natsoni 53da6549e2 Remove unused CSS 2024-07-09 18:48:33 +09:00
wiz 65046c4cb8 Change blockstream/electrs to mempool/electrs in README 2024-07-09 18:03:41 +09:00
Mononaut 9416fd25f4 [accelerator] tidy up chevron animation 2024-07-09 08:58:03 +00:00
Mononaut adde1a86e4 [accelerator] fast track chevrons animation 2024-07-09 08:57:09 +00:00
wiz 8a96669260 Merge pull request #5296 from mempool/mononaut/disable-services-proxy
[ops] disable node services api proxy on production
2024-07-09 15:38:38 +09:00
Mononaut 92434d41a4 [ops] disable services api proxy on production 2024-07-09 06:27:26 +00:00
Hans ❤️ Crypto 64dd55b44b Update block.component.html 2024-07-08 12:40:43 +02:00
Hans ❤️ Crypto e2d2a8da26 Update block-transactions.component.html 2024-07-08 12:39:49 +02:00
Hans ❤️ Crypto 0e37e85af6 Create hans-crypto.txt 2024-05-21 12:35:20 +02:00
Hans ❤️ Crypto 4b3123b5ae Remove reference to bisq in unfurler
not needed anymore
2024-05-21 09:00:05 +02:00
103 changed files with 14114 additions and 11717 deletions

No files matched your search

+15
View File
@@ -42,6 +42,7 @@ class BitcoinRoutes {
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash', this.getBlock)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/summary', this.getStrippedBlockTransactions)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/audit-summary', this.getBlockAuditSummary)
.get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/tx/:txid/audit', this.$getBlockTxAuditSummary)
.get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/height', this.getBlockTipHeight)
.post(config.MEMPOOL.API_URL_PREFIX + 'psbt/addparents', this.postPsbtCompletion)
.get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from', this.getBlocksByBulk.bind(this))
@@ -361,6 +362,20 @@ class BitcoinRoutes {
}
}
private async $getBlockTxAuditSummary(req: Request, res: Response) {
try {
const auditSummary = await blocks.$getBlockTxAuditSummary(req.params.hash, req.params.txid);
if (auditSummary) {
res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24 * 30).toUTCString());
res.json(auditSummary);
} else {
return res.status(404).send(`transaction audit not available`);
}
} catch (e) {
res.status(500).send(e instanceof Error ? e.message : e);
}
}
private async getBlocks(req: Request, res: Response) {
try {
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { // Bitcoin
+9 -1
View File
@@ -2,7 +2,7 @@ import config from '../config';
import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory';
import logger from '../logger';
import memPool from './mempool';
import { BlockExtended, BlockExtension, BlockSummary, PoolTag, TransactionExtended, TransactionMinerInfo, CpfpSummary, MempoolTransactionExtended, TransactionClassified, BlockAudit } from '../mempool.interfaces';
import { BlockExtended, BlockExtension, BlockSummary, PoolTag, TransactionExtended, TransactionMinerInfo, CpfpSummary, MempoolTransactionExtended, TransactionClassified, BlockAudit, TransactionAudit } from '../mempool.interfaces';
import { Common } from './common';
import diskCache from './disk-cache';
import transactionUtils from './transaction-utils';
@@ -1359,6 +1359,14 @@ class Blocks {
}
}
public async $getBlockTxAuditSummary(hash: string, txid: string): Promise<TransactionAudit | null> {
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) {
return BlocksAuditsRepository.$getBlockTxAudit(hash, txid);
} else {
return null;
}
}
public getLastDifficultyAdjustmentTime(): number {
return this.lastDifficultyAdjustmentTime;
}
+3 -1
View File
@@ -333,7 +333,9 @@ class Server {
if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
accelerationRoutes.initRoutes(this.app);
}
aboutRoutes.initRoutes(this.app);
if (!config.MEMPOOL.OFFICIAL) {
aboutRoutes.initRoutes(this.app);
}
}
healthCheck(): void {
+13
View File
@@ -42,6 +42,19 @@ export interface BlockAudit {
matchRate: number,
expectedFees?: number,
expectedWeight?: number,
template?: any[];
}
export interface TransactionAudit {
seen?: boolean;
expected?: boolean;
added?: boolean;
prioritized?: boolean;
delayed?: number;
accelerated?: boolean;
conflict?: boolean;
coinbase?: boolean;
firstSeen?: number;
}
export interface AuditScore {
@@ -1,7 +1,7 @@
import blocks from '../api/blocks';
import DB from '../database';
import logger from '../logger';
import { BlockAudit, AuditScore } from '../mempool.interfaces';
import { BlockAudit, AuditScore, TransactionAudit } from '../mempool.interfaces';
class BlocksAuditRepositories {
public async $saveAudit(audit: BlockAudit): Promise<void> {
@@ -98,6 +98,41 @@ class BlocksAuditRepositories {
}
}
public async $getBlockTxAudit(hash: string, txid: string): Promise<TransactionAudit | null> {
try {
const blockAudit = await this.$getBlockAudit(hash);
if (blockAudit) {
const isAdded = blockAudit.addedTxs.includes(txid);
const isPrioritized = blockAudit.prioritizedTxs.includes(txid);
const isAccelerated = blockAudit.acceleratedTxs.includes(txid);
const isConflict = blockAudit.fullrbfTxs.includes(txid);
let isExpected = false;
let firstSeen = undefined;
blockAudit.template?.forEach(tx => {
if (tx.txid === txid) {
isExpected = true;
firstSeen = tx.time;
}
});
return {
seen: isExpected || isPrioritized || isAccelerated,
expected: isExpected,
added: isAdded,
prioritized: isPrioritized,
conflict: isConflict,
accelerated: isAccelerated,
firstSeen,
}
}
return null;
} catch (e: any) {
logger.err(`Cannot fetch block transaction audit from db. Reason: ` + (e instanceof Error ? e.message : e));
throw e;
}
}
public async $getBlockAuditScore(hash: string): Promise<AuditScore> {
try {
const [rows]: any[] = await DB.query(
+3
View File
@@ -0,0 +1,3 @@
I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of May 21, 2024.
Signed: hans-crypto
+3
View File
@@ -0,0 +1,3 @@
I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 12, 2024.
Signed: jlopp
+3
View File
@@ -0,0 +1,3 @@
I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 9, 2024.
Signed: svrgnty
+1 -1
View File
@@ -149,7 +149,7 @@ __MEMPOOL_SERVICES_ACCELERATIONS__=${MEMPOOL_SERVICES_ACCELERATIONS:=false}
# REDIS
__REDIS_ENABLED__=${REDIS_ENABLED:=false}
__REDIS_UNIX_SOCKET_PATH__=${REDIS_UNIX_SOCKET_PATH:=true}
__REDIS_UNIX_SOCKET_PATH__=${REDIS_UNIX_SOCKET_PATH:=""}
__REDIS_BATCH_QUERY_BASE_SIZE__=${REDIS_BATCH_QUERY_BASE_SIZE:=5000}
# FIAT_PRICE
+2
View File
@@ -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}
__SIGNET_BLOCK_AUDIT_START_HEIGHT__=${SIGNET_BLOCK_AUDIT_START_HEIGHT:=0}
__ACCELERATOR__=${ACCELERATOR:=false}
__SERVICES_API__=${SERVICES_API:=false}
__PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false}
__HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true}
__ADDITIONAL_CURRENCIES__=${ADDITIONAL_CURRENCIES:=false}
@@ -69,6 +70,7 @@ export __MAINNET_BLOCK_AUDIT_START_HEIGHT__
export __TESTNET_BLOCK_AUDIT_START_HEIGHT__
export __SIGNET_BLOCK_AUDIT_START_HEIGHT__
export __ACCELERATOR__
export __SERVICES_API__
export __PUBLIC_ACCELERATIONS__
export __HISTORICAL_PRICE__
export __ADDITIONAL_CURRENCIES__
+2 -1
View File
@@ -25,5 +25,6 @@
"HISTORICAL_PRICE": true,
"ADDITIONAL_CURRENCIES": false,
"ACCELERATOR": false,
"PUBLIC_ACCELERATIONS": false
"PUBLIC_ACCELERATIONS": false,
"SERVICES_API": "https://mempool.space/api/v1/services"
}
+25 -28
View File
@@ -23,9 +23,9 @@
"@angular/router": "^17.3.1",
"@angular/ssr": "^17.3.1",
"@fortawesome/angular-fontawesome": "~0.14.1",
"@fortawesome/fontawesome-common-types": "~6.5.1",
"@fortawesome/fontawesome-svg-core": "~6.5.1",
"@fortawesome/free-solid-svg-icons": "~6.5.1",
"@fortawesome/fontawesome-common-types": "~6.6.0",
"@fortawesome/fontawesome-svg-core": "~6.6.0",
"@fortawesome/free-solid-svg-icons": "~6.6.0",
"@mempool/mempool.js": "2.3.0",
"@ng-bootstrap/ng-bootstrap": "^16.0.0",
"@types/qrcode": "~1.5.0",
@@ -3669,33 +3669,30 @@
}
},
"node_modules/@fortawesome/fontawesome-common-types": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
"integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==",
"hasInstallScript": true,
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz",
"integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==",
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/fontawesome-svg-core": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
"integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
"hasInstallScript": true,
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz",
"integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.5.1"
"@fortawesome/fontawesome-common-types": "6.6.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/free-solid-svg-icons": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz",
"integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==",
"hasInstallScript": true,
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz",
"integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.5.1"
"@fortawesome/fontawesome-common-types": "6.6.0"
},
"engines": {
"node": ">=6"
@@ -20797,24 +20794,24 @@
}
},
"@fortawesome/fontawesome-common-types": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
"integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A=="
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz",
"integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw=="
},
"@fortawesome/fontawesome-svg-core": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
"integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz",
"integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.5.1"
"@fortawesome/fontawesome-common-types": "6.6.0"
}
},
"@fortawesome/free-solid-svg-icons": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz",
"integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==",
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz",
"integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==",
"requires": {
"@fortawesome/fontawesome-common-types": "6.5.1"
"@fortawesome/fontawesome-common-types": "6.6.0"
}
},
"@goto-bus-stop/common-shake": {
+3 -3
View File
@@ -76,9 +76,9 @@
"@angular/router": "^17.3.1",
"@angular/ssr": "^17.3.1",
"@fortawesome/angular-fontawesome": "~0.14.1",
"@fortawesome/fontawesome-common-types": "~6.5.1",
"@fortawesome/fontawesome-svg-core": "~6.5.1",
"@fortawesome/free-solid-svg-icons": "~6.5.1",
"@fortawesome/fontawesome-common-types": "~6.6.0",
"@fortawesome/fontawesome-svg-core": "~6.6.0",
"@fortawesome/free-solid-svg-icons": "~6.6.0",
"@mempool/mempool.js": "2.3.0",
"@ng-bootstrap/ng-bootstrap": "^16.0.0",
"@types/qrcode": "~1.5.0",
@@ -2,7 +2,7 @@
@if (accelerateError) {
<div class="row mb-1 text-center">
<div class="col-sm">
<h1 style="font-size: larger;">Sorry, something went wrong!</h1>
<h1 style="font-size: larger;" i18n="accelerator.sorry-error-title">Sorry, something went wrong!</h1>
</div>
</div>
<div class="row text-center mt-1">
@@ -552,22 +552,15 @@
<ng-template #accelerateTo let-x i18n="accelerator.accelerate-to-x">Accelerate to ~{{ x | number : '1.0-0' }} sat/vB</ng-template>
<ng-template #accelerateButton>
@if (!couldPay && !quoteError && !(estimate?.availablePaymentMethods.bitcoin || estimate?.availablePaymentMethods.balance)) {
<button type="button" class="mt-1 btn btn-purple rounded-pill align-self-center d-flex flex-row justify-content-center align-items-center disabled" style="width: 200px">
<div class="position-relative">
<button type="button" class="mt-1 btn btn-purple rounded-pill align-self-center d-flex flex-row justify-content-center align-items-center" [class.disabled]="!canPay || quoteError || cantPayReason || calculating || (!advancedEnabled && selectedOption !== 'accel')" style="width: 200px" (click)="moveToStep('checkout')">
<img src="/resources/mempool-accelerator-sparkles-light.svg" height="20" class="mr-2" style="margin-left: -10px">
<span>Coming soon</span>
<span i18n="transaction.accelerate|Accelerate button label">Accelerate</span>
</button>
} @else {
<div class="position-relative">
<button type="button" class="mt-1 btn btn-purple rounded-pill align-self-center d-flex flex-row justify-content-center align-items-center" [class.disabled]="!canPay || quoteError || cantPayReason || calculating || (!advancedEnabled && selectedOption !== 'accel')" style="width: 200px" (click)="moveToStep('checkout')">
<img src="/resources/mempool-accelerator-sparkles-light.svg" height="20" class="mr-2" style="margin-left: -10px">
<span i18n="transaction.accelerate|Accelerate button label">Accelerate</span>
</button>
@if (quoteError || cantPayReason) {
<div class="btn-error-wrapper"><span class="btn-error"><app-mempool-error [error]="quoteError || cantPayReason" [textOnly]="true" alertClass=""></app-mempool-error></span></div>
}
</div>
}
@if (quoteError || cantPayReason) {
<div class="btn-error-wrapper"><span class="btn-error"><app-mempool-error [error]="quoteError || cantPayReason" [textOnly]="true" alertClass=""></app-mempool-error></span></div>
}
</div>
</ng-template>
<ng-template #accountPayButton>
@@ -8,6 +8,7 @@ import { ETA, EtaService } from '../../services/eta.service';
import { Transaction } from '../../interfaces/electrs.interface';
import { MiningStats } from '../../services/mining.service';
import { IAuth, AuthServiceMempool } from '../../services/auth.service';
import { EnterpriseService } from '../../services/enterprise.service';
export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp';
@@ -126,7 +127,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
private etaService: EtaService,
private audioService: AudioService,
private cd: ChangeDetectorRef,
private authService: AuthServiceMempool
private authService: AuthServiceMempool,
private enterpriseService: EnterpriseService,
) {
this.accelerationUUID = window.crypto.randomUUID();
}
@@ -198,6 +200,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
if (!this.estimate && ['quote', 'summary', 'checkout'].includes(this.step)) {
this.fetchEstimate();
}
if (this._step === 'checkout') {
this.enterpriseService.goal(8);
}
if (this._step === 'checkout' && this.canPayWithBitcoin) {
this.btcpayInvoiceFailed = false;
this.loadingBtcpayInvoice = true;
@@ -292,6 +297,14 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
this.validateChoice();
if (!this.couldPay) {
this.quoteError = `cannot_accelerate_tx`;
if (this.step === 'summary') {
this.unavailable.emit(true);
}
return;
}
if (this.step === 'checkout' && this.canPayWithBitcoin && !this.loadingBtcpayInvoice) {
this.loadingBtcpayInvoice = true;
this.requestBTCPayInvoice();
@@ -546,7 +559,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
}
get couldPayWithCashapp() {
if (!this.cashappEnabled || this.stateService.referrer !== 'https://cash.app/') {
if (!this.cashappEnabled) {
return false;
}
return !!this.estimate?.availablePaymentMethods?.cashapp;
@@ -569,7 +582,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
}
get canPayWithCashapp() {
if (!this.cashappEnabled || !this.conversions || this.stateService.referrer !== 'https://cash.app/') {
if (!this.cashappEnabled || !this.conversions) {
return false;
}
@@ -88,7 +88,7 @@ export class AccelerateFeeGraphComponent implements OnInit, AfterViewInit, OnCha
rate: option.rate,
height: lastHeight,
class: 'max',
label: this.showEstimate ? $localize`maximum` : $localize`:@@25fbf6e80a945703c906a5a7d8c92e8729c7ab21:accelerated`,
label: this.showEstimate ? $localize`maximum` : $localize`accelerated`,
active: option.index === this.maxRateIndex,
rateIndex: option.index,
fee: option.fee,
@@ -1,6 +1,38 @@
@if (tx.status.confirmed) {
<div class="acceleration-timeline box">
<div class="acceleration-timeline box" [class.lower-padding]="!tx.status.confirmed">
<div class="timeline-wrapper">
@if (!tx.status.confirmed) {
<div class="timeline">
<div class="intervals">
<div class="node-spacer"></div>
<div class="interval-spacer"></div>
<div class="node-spacer"></div>
<div class="interval">
<div class="interval-time">
@if (eta) {
~<app-time [time]="eta?.wait / 1000"></app-time> <!-- <span *ngIf="accelerateRatio > 1" class="compare"> ({{ accelerateRatio }}x faster)</span> -->
}
</div>
</div>
<div class="node-spacer"></div>
</div>
<div class="nodes">
<div class="node-spacer"></div>
<div class="interval-spacer"></div>
<div class="node">
<div class="acc-to-confirmed right go-faster"></div>
</div>
<div class="interval-spacer">
</div>
<div class="node" [id]="'confirmed'">
<div class="acc-to-confirmed left go-faster"></div>
<div class="shape-border waiting">
<div class="shape animate"></div>
</div>
<div class="status"><span class="badge badge-waiting" i18n="transaction.rbf.mined">Mined</span></div>
</div>
</div>
</div>
}
<div class="timeline">
<div class="intervals">
<div class="node-spacer"></div>
@@ -12,7 +44,13 @@
<div class="node-spacer"></div>
<div class="interval">
<div class="interval-time">
<app-time [time]="tx.status.block_time - acceleratedAt"></app-time>
@if (tx.status.confirmed) {
<div class="interval-time">
<app-time [time]="tx.status.block_time - acceleratedAt"></app-time>
</div>
} @else if (standardETA && !tx.status.confirmed) {
<!-- ~<app-time [time]="standardETA / 1000 - now"></app-time> -->
}
</div>
</div>
<div class="node-spacer"></div>
@@ -25,128 +63,71 @@
</div>
<div class="status"><span class="badge badge-primary" i18n="transaction.first-seen|Transaction first seen">First seen</span></div>
<div class="time">
<app-time *ngIf="transactionTime > 0" kind="since" [time]="transactionTime"></app-time>
@if (useAbsoluteTime) {
<span>{{ transactionTime * 1000 | date }}</span>
} @else {
<app-time kind="since" [time]="transactionTime"></app-time>
}
</div>
</div>
<div class="interval-spacer">
<div class="seen-to-acc"></div>
</div>
<div class="node" [id]="'accelerated'">
<div class="node" [class.accelerated]="!tx.status.confirmed" [id]="'accelerated'">
<div class="seen-to-acc left"></div>
<div class="acc-to-confirmed right"></div>
<div class="shape-border">
@if (tx.status.confirmed) {
<div class="acc-to-confirmed right"></div>
} @else {
<div class="seen-to-acc right"></div>
}
<div class="shape-border">
<div class="shape"></div>
@if (!tx.status.confirmed) {
<div class="connector down loading"></div>
}
</div>
<div class="status"><span class="badge badge-accelerated" i18n="transaction.audit.accelerated">Accelerated</span></div>
<div class="time">
<app-time *ngIf="acceleratedAt" kind="since" [time]="acceleratedAt"></app-time>
@if (tx.status.confirmed) {
<div class="status"><span class="badge badge-accelerated" i18n="transaction.audit.accelerated">Accelerated</span></div>
}
<div class="time offset-left" [class.no-margin]="!tx.status.confirmed">
@if (!tx.status.confirmed) {
<span i18n="transaction.audit.accelerated">Accelerated</span>{{ "" }}
}
@if (useAbsoluteTime) {
<span>{{ acceleratedAt * 1000 | date }}</span>
} @else {
<app-time kind="since" [time]="acceleratedAt" [lowercaseStart]="true"></app-time>
}
</div>
</div>
<div class="interval-spacer">
@if (tx.status.confirmed) {
<div class="acc-to-confirmed"></div>
} @else {
<div class="seen-to-acc"></div>
}
</div>
<div class="node mined" [id]="'confirmed'" >
<div class="acc-to-confirmed left" ></div>
<div class="shape-border mined-selected">
<div class="node" [class.selected]="tx.status.confirmed" [id]="'confirmed'">
@if (tx.status.confirmed) {
<div class="acc-to-confirmed left"></div>
} @else {
<div class="seen-to-acc left"></div>
}
<div class="shape-border" [class.waiting]="!tx.status.confirmed">
<div class="shape"></div>
</div>
@if (tx.status.confirmed) {
<div class="status"><span class="badge badge-success" i18n="transaction.rbf.mined">Mined</span></div>
<div class="time">
@if (useAbsoluteTime) {
<span>{{ tx.status.block_time * 1000 | date }}</span>
} @else {
<app-time kind="since" [time]="tx.status.block_time"></app-time>
}
</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
} @else if (acceleratedETA) { <!-- Not yet accelerated; to be shown only in acceleration checkout -->
} @else if (standardETA) { <!-- Accelerated -->
<div class="acceleration-timeline box">
<div class="timeline-wrapper">
<div class="timeline">
<div class="intervals">
<div class="node-spacer"></div>
<div class="interval-spacer"></div>
<div class="node-spacer"></div>
<div class="interval">
<div class="interval-time">
@if (eta) {
~<app-time [time]="eta?.wait / 1000"></app-time> <span *ngIf="accelerateRatio > 1" class="compare"> ({{ accelerateRatio }}x faster)</span>
}
</div>
</div>
<div class="node-spacer"></div>
</div>
<div class="nodes">
<div class="node-spacer"></div>
<div class="interval-spacer"></div>
<div class="node">
<div class="acc-to-confirmed loading right"></div>
</div>
<div class="interval-spacer">
<div class="acc-to-confirmed loading"></div>
</div>
<div class="node" [id]="'confirmed'">
<div class="acc-to-confirmed loading left"></div>
<div class="shape-border waiting">
<div class="shape animate"></div>
</div>
<div class="status"><span class="badge badge-waiting" i18n="transaction.rbf.mined">Mined</span></div>
</div>
</div>
</div>
<div class="timeline">
<div class="intervals">
<div class="node-spacer"></div>
<div class="interval">
<div class="interval-time">
<app-time [time]="acceleratedAt - transactionTime"></app-time>
</div>
</div>
<div class="node-spacer"></div>
<div class="interval">
<div class="interval-time">
~<app-time [time]="standardETA / 1000 - now"></app-time>
</div>
</div>
<div class="node-spacer"></div>
</div>
<div class="nodes">
<div class="node" [id]="'first-seen'">
<div class="seen-to-acc right"></div>
<div class="shape-border">
<div class="shape"></div>
</div>
<div class="status"><span class="badge badge-primary" i18n="transaction.first-seen|Transaction first seen">First seen</span></div>
<div class="time">
<app-time *ngIf="transactionTime > 0" kind="since" [time]="transactionTime"></app-time>
</div>
</div>
<div class="interval-spacer">
<div class="seen-to-acc"></div>
</div>
<div class="node" [id]="'accelerated'">
<div class="seen-to-acc left"></div>
<div class="seen-to-acc right"></div>
<div class="shape-border accelerated-selected">
<div class="shape accelerating"></div>
<div class="connector down loading"></div>
</div>
<div class="time" style="margin-top: 3px;">
<span i18n="transaction.audit.accelerated">Accelerated</span>&nbsp;<app-time *ngIf="acceleratedAt" kind="since" [time]="acceleratedAt"></app-time>
</div>
</div>
<div class="interval-spacer">
<div class="seen-to-acc"></div>
</div>
<div class="node" [id]="'confirmed'">
<div class="seen-to-acc left"></div>
<div class="shape-border waiting">
<div class="shape"></div>
</div>
</div>
</div>
</div>
</div>
</div>
}
@@ -1,7 +1,10 @@
.acceleration-timeline {
position: relative;
width: 100%;
padding: 0.5em 0 1em;
padding: 1em 0;
&.lower-padding {
padding: 0.5em 0 1em;
}
&::after, &::before {
content: '';
@@ -52,7 +55,7 @@
.interval, .interval-spacer {
width: 8em;
min-width: 5em;
min-width: 8em;
max-width: 8em;
height: 32px;
display: flex;
@@ -112,8 +115,20 @@
background: var(--tertiary);
border-radius: 5px;
&.loading {
animation: acceleratePulse 1s infinite;
&.go-faster {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='10'%3E%3Cpath style='fill:%239339f4;' d='M 0,0 5,5 0,10 Z'/%3E%3Cpath style='fill:%23653b9c;' d='M 0,0 10,0 15,5 10,10 0,10 5,5 Z'/%3E%3Cpath style='fill:%239339f4;' d='M 10,0 20,0 20,10 10,10 15,5 Z'/%3E%3C/svg%3E%0A"); background-size: 20px 10px;
border-radius: 0;
&.right {
left: calc(50% + 5px);
margin-right: calc(-4em + 5px);
animation: goFasterRight 0.8s infinite linear;
}
&.left {
right: calc(50% + 5px);
margin-left: calc(-4em + 5px);
animation: goFasterLeft 0.8s infinite linear;
}
}
&.left {
@@ -123,28 +138,6 @@
left: 50%;
}
}
.connector {
position: absolute;
height: 88px;
width: 10px;
left: -5px;
top: -73px;
transform: translateX(120%);
background: var(--tertiary);
&.down {
border-top-left-radius: 10px;
}
&.up {
border-top-right-radius: 10px;
}
&.loading {
animation: acceleratePulse 1s infinite;
}
}
}
.nodes {
@@ -159,16 +152,17 @@
margin-bottom: -8px;
transform: translateY(-50%);
border-radius: 50%;
padding: 2px;
cursor: pointer;
padding: 4px;
background: transparent;
.shape {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
background: white;
&.accelerating {
animation: acceleratePulse 1s infinite;
}
z-index: 1;
}
&.waiting {
@@ -176,22 +170,46 @@
background: var(--grey);
}
}
&.accelerated-selected {
.shape {
background: var(--tertiary);
.connector {
position: absolute;
z-index: 0;
height: 88px;
width: 10px;
left: -5px;
top: -73px;
transform: translateX(120%);
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='20'%3E%3Cpath style='fill:%239339f4;' d='M 0,20 5,15 10,20 Z'/%3E%3Cpath style='fill:%23653b9c;' d='M 0,20 5,15 10,20 10,10 5,5 0,10 Z'/%3E%3Cpath style='fill:%239339f4;' d='M 0,10 5,5 10,10 10,0 0,0 Z'/%3E%3C/svg%3E%0A"); // linear-gradient(135deg, var(--tertiary) 34%, transparent 34%),
background-size: 10px 20px;
&.down {
border-top-left-radius: 10px;
}
&.up {
border-top-right-radius: 10px;
}
&.loading {
animation: goFasterUp 0.8s infinite linear;
}
}
}
&.accelerated {
.shape-border {
animation: acceleratePulse 0.4s infinite;
}
}
&.mined-selected {
.shape {
background: var(--success);
}
&.selected {
.shape-border {
background: var(--mainnet-alt);
}
}
.status {
margin-top: -64px;
margin-top: -66px;
.badge.badge-waiting {
opacity: 0.5;
@@ -206,10 +224,20 @@
}
.time {
margin-top: 33px;
margin-top: 32px;
font-size: 12px;
line-height: 16px;
white-space: nowrap;
&.offset-left {
@media (max-width: 650px) {
margin-left: -20px;
}
}
&.no-margin {
margin-top: 0px;
}
}
}
}
@@ -220,3 +248,18 @@
50% { background-color: var(--mainnet-alt) }
100% { background-color: var(--tertiary) }
}
@keyframes goFasterUp {
0% { background-position-y: 0; }
100% { background-position-y: -40px; }
}
@keyframes goFasterLeft {
0% { background-position: left 0px bottom 0px }
100% { background-position: left 40px bottom 0px; }
}
@keyframes goFasterRight {
0% { background-position: right 0 bottom 0px; }
100% { background-position: right -40px bottom 0px; }
}
@@ -19,23 +19,37 @@ export class AccelerationTimelineComponent implements OnInit, OnChanges {
acceleratedAt: number;
now: number;
accelerateRatio: number;
useAbsoluteTime: boolean = false;
interval: number;
constructor() {}
ngOnInit(): void {
this.acceleratedAt = this.tx.acceleratedAt ?? new Date().getTime() / 1000;
this.now = Math.floor(new Date().getTime() / 1000);
this.useAbsoluteTime = this.tx.status.block_time < this.now - 7 * 24 * 3600;
this.interval = window.setInterval(() => {
this.now = Math.floor(new Date().getTime() / 1000);
this.useAbsoluteTime = this.tx.status.block_time < this.now - 7 * 24 * 3600;
}, 60000);
}
ngOnChanges(changes): void {
this.now = Math.floor(new Date().getTime() / 1000);
if (changes?.eta?.currentValue || changes?.standardETA?.currentValue || changes?.acceleratedETA?.currentValue) {
if (changes?.eta?.currentValue) {
if (changes?.acceleratedETA?.currentValue) {
this.accelerateRatio = Math.floor((Math.floor(changes.eta.currentValue.time / 1000) - this.now) / (Math.floor(changes.acceleratedETA.currentValue / 1000) - this.now));
} else if (changes?.standardETA?.currentValue) {
this.accelerateRatio = Math.floor((Math.floor(changes.standardETA.currentValue / 1000) - this.now) / (Math.floor(changes.eta.currentValue.time / 1000) - this.now));
}
}
}
// Hide standard ETA while we don't have a proper standard ETA calculation, see https://github.com/mempool/mempool/issues/65
// if (changes?.eta?.currentValue || changes?.standardETA?.currentValue || changes?.acceleratedETA?.currentValue) {
// if (changes?.eta?.currentValue) {
// if (changes?.acceleratedETA?.currentValue) {
// this.accelerateRatio = Math.floor((Math.floor(changes.eta.currentValue.time / 1000) - this.now) / (Math.floor(changes.acceleratedETA.currentValue / 1000) - this.now));
// } else if (changes?.standardETA?.currentValue) {
// this.accelerateRatio = Math.floor((Math.floor(changes.standardETA.currentValue / 1000) - this.now) / (Math.floor(changes.eta.currentValue.time / 1000) - this.now));
// }
// }
// }
}
ngOnDestroy(): void {
clearInterval(this.interval);
}
}
@@ -45,8 +45,8 @@
</form>
</div>
<div [class.chart]="!widget" [class.chart-widget]="widget" *browserOnly [style]="{ height: widget ? ((height + 20) + 'px') : null}" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
(chartInit)="onChartInit($event)" [style]="{opacity: isLoading ? 0.5 : 1}">
<div [class.chart]="!widget" [class.chart-widget]="widget" *browserOnly [style]="{ height: widget ? ((height + 20) + 'px') : null, opacity: isLoading ? 0.5 : 1 }" echarts [initOpts]="chartInitOptions" [options]="chartOptions"
(chartInit)="onChartInit($event)">
</div>
<div class="text-center loadingGraphs" *ngIf="!stateService.isBrowser || isLoading">
<div class="spinner-border text-light"></div>
@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { EChartsOption } from '../../../graphs/echarts';
import { Observable, Subject, Subscription, combineLatest, fromEvent, merge, share } from 'rxjs';
import { startWith, switchMap, tap } from 'rxjs/operators';
@@ -8,10 +8,11 @@ import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from '../../../shared/graphs.utils';
import { StorageService } from '../../../services/storage.service';
import { MiningService } from '../../../services/mining.service';
import { ActivatedRoute } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { Acceleration } from '../../../interfaces/node-api.interface';
import { ServicesApiServices } from '../../../services/services-api.service';
import { StateService } from '../../../services/state.service';
import { RelativeUrlPipe } from '../../../shared/pipes/relative-url/relative-url.pipe';
@Component({
selector: 'app-acceleration-fees-graph',
@@ -32,7 +33,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
@Input() height: number = 300;
@Input() right: number | string = 45;
@Input() left: number | string = 75;
@Input() period: '3d' | '1w' | '1m' = '1w';
@Input() period: '24h' | '3d' | '1w' | '1m' | 'all' = '1w';
@Input() accelerations$: Observable<Acceleration[]>;
miningWindowPreference: string;
@@ -48,7 +49,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
isLoading = true;
formatNumber = formatNumber;
timespan = '';
periodSubject$: Subject<'3d' | '1w' | '1m'> = new Subject();
periodSubject$: Subject<'24h' | '3d' | '1w' | '1m' | 'all'> = new Subject();
chartInstance: any = undefined;
daysAvailable: number = 0;
@@ -62,6 +63,8 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
private route: ActivatedRoute,
public stateService: StateService,
private cd: ChangeDetectorRef,
private router: Router,
private zone: NgZone,
) {
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1w' });
this.radioGroupForm.controls.dateSpan.setValue('1w');
@@ -78,7 +81,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
this.route.fragment.subscribe((fragment) => {
if (['24h', '3d', '1w', '1m', '3m'].indexOf(fragment) > -1) {
if (['24h', '3d', '1w', '1m', '3m', 'all'].indexOf(fragment) > -1) {
this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false });
}
});
@@ -294,6 +297,19 @@ export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDest
onChartInit(ec) {
this.chartInstance = ec;
this.chartInstance.on('click', (e) => {
this.zone.run(() => {
if (['24h', '3d'].includes(this.timespan)) {
const url = new RelativeUrlPipe(this.stateService).transform(`/block/${e.data[2]}`);
if (e.event.event.shiftKey || e.event.event.ctrlKey || e.event.event.metaKey) {
window.open(url);
} else {
this.router.navigate([url]);
}
}
});
});
}
isMobile() {
@@ -4,7 +4,7 @@
<h5 class="card-title" i18n="accelerator.requests">Requests</h5>
<div class="card-text">
<div>{{ stats.totalRequested }}</div>
<div class="symbol" i18n="accelerator.total-accelerated">accelerated</div>
<div class="symbol" i18n="accelerator.total-accelerated-plural">accelerated</div>
</div>
</div>
<div class="item">
@@ -16,7 +16,7 @@ export type AccelerationStats = {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AccelerationStatsComponent implements OnInit, OnChanges {
@Input() timespan: '3d' | '1w' | '1m' = '1w';
@Input() timespan: '24h' | '3d' | '1w' | '1m' | 'all' = '1w';
accelerationStats$: Observable<AccelerationStats>;
blocksInPeriod: number = 7 * 144;
@@ -35,6 +35,9 @@ export class AccelerationStatsComponent implements OnInit, OnChanges {
updateStats(): void {
this.accelerationStats$ = this.servicesApiService.getAccelerationStats$({ timeframe: this.timespan });
switch (this.timespan) {
case '24h':
this.blocksInPeriod = 144;
break;
case '3d':
this.blocksInPeriod = 3 * 144;
break;
@@ -44,6 +47,9 @@ export class AccelerationStatsComponent implements OnInit, OnChanges {
case '1m':
this.blocksInPeriod = 30 * 144;
break;
case 'all':
this.blocksInPeriod = Infinity;
break;
}
}
}
@@ -23,12 +23,18 @@
<div class="main-title">
<span [attr.data-cy]="'acceleration-stats'" i18n="accelerator.acceleration-stats">Acceleration stats</span>&nbsp;
@switch (timespan) {
@case ('24h') {
<span style="font-size: xx-small" i18n="mining.1-day">(1 day)</span>
}
@case ('1w') {
<span style="font-size: xx-small" i18n="mining.1-week">(1 week)</span>
}
@case ('1m') {
<span style="font-size: xx-small" i18n="mining.1-month">(1 month)</span>
}
@case ('all') {
<span style="font-size: xx-small" i18n="mining.all-time">(all time)</span>
}
}
</div>
<div class="card-wrapper">
@@ -36,11 +42,17 @@
<div class="card-body more-padding">
<app-acceleration-stats [timespan]="timespan"></app-acceleration-stats>
<div class="widget-toggler">
<a href="" (click)="setTimespan('24h')" class="toggler-option"
[ngClass]="{'inactive': timespan === '24h'}"><small>24h</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('1w')" class="toggler-option"
[ngClass]="{'inactive': timespan === '1w'}"><small>1w</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('1m')" class="toggler-option"
[ngClass]="{'inactive': timespan === '1m'}"><small>1m</small></a>
<span style="color: #ffffff66; font-size: 8px"> | </span>
<a href="" (click)="setTimespan('all')" class="toggler-option"
[ngClass]="{'inactive': timespan === 'all'}"><small>all</small></a>
</div>
</div>
</div>
@@ -37,7 +37,7 @@ export class AcceleratorDashboardComponent implements OnInit, OnDestroy {
webGlEnabled = true;
seen: Set<string> = new Set();
firstLoad = true;
timespan: '3d' | '1w' | '1m' = '1w';
timespan: '24h' | '3d' | '1w' | '1m' | 'all' = '1w';
accelerationDeltaSubscription: Subscription;
@@ -99,7 +99,7 @@ export class AcceleratorDashboardComponent implements OnInit, OnDestroy {
this.minedAccelerations$ = this.stateService.chainTip$.pipe(
distinctUntilChanged(),
switchMap(() => {
return this.serviceApiServices.getAccelerationHistory$({ status: 'completed', pageLength: 6 }).pipe(
return this.serviceApiServices.getAccelerationHistory$({ status: 'completed_provisional,completed', pageLength: 6 }).pipe(
catchError(() => {
return of([]);
}),
@@ -18,7 +18,12 @@
</div>
</td>
<td class="pie-chart" rowspan="2" *ngIf="!chartPositionLeft">
<ng-container *ngTemplateOutlet="pieChart"></ng-container>
<div class="d-flex justify-content-between align-items-start">
@if (hasCpfp) {
<button type="button" class="btn btn-outline-info btn-sm btn-small-height float-right mt-0" (click)="onToggleCpfp()">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button>
}
<ng-container *ngTemplateOutlet="pieChart"></ng-container>
</div>
</td>
</tr>
<tr>
@@ -27,6 +32,15 @@
<ng-container i18n="accelerator.x-of-hash-rate">{{ acceleratedByPercentage }} <span class="symbol hashrate-label">of hashrate</span></ng-container>
</td>
</tr>
@if (hasCpfp && chartPositionLeft) {
<tr>
<td colspan="3" class="pt-0">
<div class="d-flex justify-content-end align-items-start">
<button type="button" class="btn btn-outline-info btn-sm btn-small-height float-right mt-0" (click)="onToggleCpfp()">CPFP <fa-icon [icon]="['fas', 'info-circle']" [fixedWidth]="true"></fa-icon></button>
</div>
</td>
</tr>
}
</tbody>
</table>
}
@@ -1,4 +1,4 @@
import { Component, ChangeDetectionStrategy, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Component, ChangeDetectionStrategy, Input, Output, OnChanges, SimpleChanges, EventEmitter } from '@angular/core';
import { Transaction } from '../../../interfaces/electrs.interface';
import { Acceleration, SinglePoolStats } from '../../../interfaces/node-api.interface';
import { EChartsOption, PieSeriesOption } from '../../../graphs/echarts';
@@ -27,8 +27,10 @@ export class ActiveAccelerationBox implements OnChanges {
@Input() accelerationInfo: Acceleration;
@Input() miningStats: MiningStats;
@Input() pools: number[];
@Input() hasCpfp: boolean = false;
@Input() chartOnly: boolean = false;
@Input() chartPositionLeft: boolean = false;
@Output() toggleCpfp = new EventEmitter();
acceleratedByPercentage: string = '';
@@ -133,4 +135,8 @@ export class ActiveAccelerationBox implements OnChanges {
}
this.chartInstance = ec;
}
onToggleCpfp(): void {
this.toggleCpfp.emit();
}
}
@@ -74,7 +74,10 @@ export class BitcoinInvoiceComponent implements OnInit, OnChanges, OnDestroy {
}
this.paymentStatusSubscription = this.apiService.getPaymentStatus$(this.invoice.btcpayInvoiceId).pipe(
retry({ delay: () => timer(2000)})
).subscribe((result) => {
).subscribe((response) => {
if (response.status === 204 || response.status === 404) {
return;
}
this.paymentStatus = 3;
this.completed.emit();
});
@@ -33,6 +33,7 @@
.menu-toggle {
width: 3em;
min-width: 3em;
height: 1.8em;
padding: 0px 1px;
opacity: 0;
@@ -42,6 +43,7 @@
border: none;
border-radius: 0.35em;
pointer-events: all;
align-self: normal;
}
.filter-menu {
@@ -52,9 +52,9 @@
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
<td i18n="block.miner">Miner</td>
<td *ngIf="stateService.env.MINING_DASHBOARD">
<a [attr.data-cy]="'block-details-miner-badge'" placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block?.extras.pool.slug]" class="badge"
[class]="!block?.extras.pool.name || block?.extras.pool.slug === 'unknown' ? 'badge-secondary' : 'badge-primary'">
{{ block?.extras.pool.name }}
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]" class="badge" style="color: #FFF;padding:0;">
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
{{ block.extras.pool.name }}
</a>
</td>
<td *ngIf="!stateService.env.MINING_DASHBOARD && stateService.env.BASE_MODULE === 'mempool'">
@@ -65,3 +65,11 @@
.badge {
transition: none;
}
.pool-logo {
width: 25px;
height: 25px;
position: relative;
top: -1px;
margin-right: 2px;
}
@@ -20,7 +20,7 @@
</ng-template>
<ng-template #loading>
<div class="text-center mb-4" class="tx-skeleton">
<div class="tx-skeleton">
<ng-container *ngIf="(txsLoadingStatus$ | async) as txsLoadingStatus; else headerLoader">
<div class="header-bg box">
<div class="progress progress-dark" style="margin: 4px; height: 14px;">
@@ -338,7 +338,7 @@
<ngb-pagination class="pagination-container float-right" [disabled]="true" [collectionSize]="block.tx_count" [rotate]="true" [pageSize]="stateService.env.ITEMS_PER_PAGE" [maxSize]="paginationMaxSize" [boundaryLinks]="true" [ellipses]="false"></ngb-pagination>
</div>
<div class="clearfix"></div>
<div class="text-center mb-4" class="tx-skeleton">
<div class="tx-skeleton">
<div class="header-bg box">
<span class="skeleton-loader"></span>
@@ -411,7 +411,7 @@
<td class="text-wrap">
<app-amount [satoshis]="block.extras.totalFees" digitsInfo="1.2-3" [noFiat]="true"></app-amount>
<span *ngIf="oobFees" class="oobFees" i18n-ngbTooltip="Acceleration Fees" ngbTooltip="Acceleration fees paid out-of-band">
<app-amount [satoshis]="oobFees" digitsInfo="1.2-8" [noFiat]="true" [addPlus]="true"></app-amount>
<app-amount [satoshis]="oobFees" digitsInfo="1.8-8" [noFiat]="true" [addPlus]="true"></app-amount>
</span>
<span *ngIf="blockAudit.feeDelta" class="difference" [class.positive]="blockAudit.feeDelta <= 0" [class.negative]="blockAudit.feeDelta > 0">
{{ blockAudit.feeDelta < 0 ? '+' : '' }}{{ (-blockAudit.feeDelta * 100) | amountShortener: 2 }}%
@@ -59,7 +59,7 @@
<app-time kind="since" [time]="block.timestamp" [fastRender]="true" [precision]="1" minUnit="minute"></app-time></div>
</ng-container>
</div>
<div class="animated" [class]="markHeight === block.height ? 'hide' : 'show'" *ngIf="block.extras?.pool != undefined && showPools">
<div class="animated" *ngIf="block.extras?.pool != undefined && showPools">
<a [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-pool'" class="badge" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
{{ block.extras.pool.name}}
@@ -86,7 +86,7 @@
</ng-template>
</div>
<div [hidden]="!arrowVisible" id="arrow-up" [style.transition]="arrowTransition"
[ngStyle]="{'left': arrowLeftPx + 'px' }"></div>
[ngStyle]="{'left': arrowLeftPx + 8 + 'px' }"></div>
</div>
<ng-template #loadingBlocksTemplate>
@@ -125,12 +125,12 @@
#arrow-up {
position: relative;
left: calc(var(--block-size) * 0.6);
top: calc(var(--block-size) * 1.12);
top: calc(var(--block-size) * 1.28);
width: 0;
height: 0;
border-left: calc(var(--block-size) * 0.3) solid transparent;
border-right: calc(var(--block-size) * 0.3) solid transparent;
border-bottom: calc(var(--block-size) * 0.3) solid var(--fg);
border-left: calc(var(--block-size) * 0.2) solid transparent;
border-right: calc(var(--block-size) * 0.2) solid transparent;
border-bottom: calc(var(--block-size) * 0.2) solid var(--fg);
}
.flashing {
@@ -170,15 +170,8 @@
.animated {
transition: all 0.15s ease-in-out;
}
.show {
opacity: 1;
white-space: nowrap;
}
.hide {
opacity: 0.4;
pointer-events : none;
}
.time-ltr {
.bitcoin-block {
@@ -14,8 +14,7 @@
}
.blockchain-wrapper {
height: 250px;
height: 260px;
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
@@ -57,7 +56,7 @@
color: var(--fg);
font-size: 0.8rem;
position: absolute;
bottom: -1.8em;
bottom: -2.2em;
left: 1px;
transform: translateX(-50%);
background: none;
@@ -114,7 +114,7 @@
#arrow-up {
position: relative;
right: calc(var(--block-size) * 0.6);
top: calc(var(--block-size) * 1.12);
top: calc(var(--block-size) * 1.20);
width: 0;
height: 0;
border-left: calc(var(--block-size) * 0.3) solid transparent;
@@ -34,7 +34,12 @@
<li class="nav-item d-flex justify-content-start align-items-center menu-click">
<fa-icon class="menu-click" [icon]="['fas', item.faIcon]" [fixedWidth]="true"></fa-icon>
<button *ngIf="item.link === 'logout'" class="btn nav-link menu-click" role="tab" (click)="logout()">{{ item.title }}</button>
<a *ngIf="item.title !== 'Logout'" class="nav-link menu-click" [routerLink]="[item.link]" role="tab">{{ item.title }}</a>
<a *ngIf="item.title !== 'Logout'" class="nav-link menu-click" [routerLink]="[item.link]" role="tab">
{{ item.title }}
@if (item.isExternal === true) {
<fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="margin-left: 5px; font-size: 13px; color: lightgray"></fa-icon>
}
</a>
</li>
</ul>
</div>
@@ -13,7 +13,7 @@
<h4>USE YOUR OWN SELF-HOSTED MEMPOOL EXPLORER</h4>
<p>For maximum privacy, we recommend that you use your own self-hosted instance of The Mempool Open Source Project&reg; on your own hardware. You can easily install your own self-hosted instance of this website on a Raspberry Pi using a one-click installation method maintained by various Bitcoin fullnode distributions such as Umbrel, RaspiBlitz, MyNode, and RoninDojo. See our project's GitHub page for more details about self-hosting this website. By using your own self-hosted instance you will have maximum security, privacy and freedom.</p>
<p>For maximum privacy, we recommend that you use your own self-hosted instance of The Mempool Open Source Project&reg;; on your own hardware. You can easily install your own self-hosted instance of this website on a Raspberry Pi using a one-click installation method maintained by various Bitcoin fullnode distributions such as Umbrel, RaspiBlitz, MyNode, and RoninDojo. See our project's GitHub page for more details about self-hosting this website. By using your own self-hosted instance you will have maximum security, privacy and freedom.</p>
<br>
@@ -27,7 +27,7 @@
<br>
<h4>BROWSING THIS WEBSITE</h4>
<h4>General</h4>
<p *ngIf="officialMempoolSpace">Out of respect for the Bitcoin community, this Website does not use any third-party analytics, third-party trackers, or third-party cookies, and we do not share any private user data with third-parties. Additionally, to mitigate the risk of surveillance by malicious third-parties, we self-host this Website on our own hardware and network infrastructure, so there are no "hosting companies" or "cloud providers" involved with the operation of this Website.</p>
@@ -41,19 +41,15 @@
<li>We use a self-hosted statistics application (matomo) for analytics purposes, which collects your IP address along with the requests you make. Our matomo instance is configured to respect your privacy by redacting your IP address and other methods, and we do not share this data with any third-party. To conceal your activity from our analytics, we recommend that you use a privacy protecting browser extension that blocks matomo from being loaded.</li>
<br>
<li>Mempool Accelerator Services are only available to persons in eligible countries, and in our discretion we may not provide Services (or may provide limited services) in one or more countries from time to time or determine that one or more countries are Restricted Jurisdictions.</li>
</ul>
<br>
<h4>USING MEMPOOL ACCELERATOR™</h4>
<h4>USING MEMPOOL ACCELERATOR&trade;</h4>
<p *ngIf="officialMempoolSpace">If you use Mempool Accelerator™ your acceleration request will be sent to us and relayed to Mempool Mining Pool Partners. We will store the TXID of the transactions you accelerate with us. We share this information with our mining pool partners, as well as publicly displaying accelerated transaction details on our website and APIs. No personal information or account identifier will be shared with any third party including mining pool partners.</p>
<p *ngIf="officialMempoolSpace">If you use Mempool Accelerator&trade; your acceleration request will be sent to us and relayed to Mempool's mining pool partners. We will store the TXID of the transactions you accelerate with us. We share this information with our mining pool partners, and publicly display accelerated transaction details on our website and APIs. No personal information or account identifiers will be shared with any third party including mining pool partners.</p>
<p *ngIf="!officialMempoolSpace">If you click the accelerate button on a transaction you will load acceleration pricing information from Mempool. If you make an acceleration request the TXID and your maximum bid will be sent to Mempool who store and share this information with their mining pool partners, as well as publicly displaying accelerated transaction details on mempool.space and Mempool APIs. No personal information or account identifier will be shared with any third party including mining pool partners.</p>
<p *ngIf="!officialMempoolSpace">If you click the accelerate button on a transaction you will load acceleration pricing information from Mempool. If you make an acceleration request, the TXID and your maximum bid will be sent to Mempool who will store and share this information with their mining pool partners, and publicly display accelerated transaction details on mempool.space and via Mempool's APIs. No personal information or account identifiers will be shared with any third party including mining pool partners.</p>
<br>
@@ -65,13 +61,13 @@
<ul>
<li>Your e-mail address and/or country, we may use this information to manage your user account, for billing purposes, or to update you about our services. We will not share this with any third-party, except as necessary for our fiat payment processor (see "Payments" below).</li>
<li>Your e-mail address and/or country; we may use this information to manage your user account, for billing purposes, or to update you about our services. We will not share this with any third-party, except as necessary for our fiat payment processor (see "Payments" below).</li>
<li>If you connect your X (fka Twitter) account, we may store your X identity, e-mail address, and profile photo. We may publicly display your profile photo or link to your profile on our website, if you sponsor The Mempool Open Source Project, claim your Lightning node, or other such use cases.</li>
<li>If you connect your X (fka Twitter) account, we may store your X identity, e-mail address, and profile photo. We may publicly display your profile photo or link to your profile on our website, if you sponsor The Mempool Open Source Project&reg;, claim your Lightning node, or other such use cases.</li>
<li>If you sign up for a subscription to Mempool Enterprise we also collect your company name which is not shared with any third-party.</li>
<li>If you sign up for a subscription to Mempool Enterprise&trade; we also collect your company name which is not shared with any third-party.</li>
<li>If you sign up for an account on mempool.space and use Mempool Accelerator Pro your accelerated transactions will be associated with your account for the purposes of accounting.</li>
<li>If you sign up for an account on mempool.space and use Mempool Accelerator&trade; Pro your accelerated transactions will be associated with your account for the purposes of accounting.</li>
</ul>
@@ -81,15 +77,15 @@
<h4>PAYMENTS AND DONATIONS</h4>
<p>If you make any payment to Mempool or donation to The Mempool Open Source Project, we may collect the following:</p>
<p>If you make any payment to Mempool or donation to The Mempool Open Source Project&reg;, we may collect the following:</p>
<ul>
<li>Your e-mail address and/or country, we may use this information to manage your user account, for billing purposes, or to update you about our services. We will not share this with any third-party, except as necessary for our fiat payment processor (see "Payments" below).</li>
<li>Your e-mail address and/or country; we may use this information to manage your user account, for billing purposes, or to update you about our services. We will not share this with any third-party, except as necessary for our fiat payment processor.</li>
<li>If you make a payment using Bitcoin, we will process your payment using our self-hosted BTCPay Server instance. We will not share your payment details with any third-party. For payments made over the Lightning network, we may utilize third party LSPs / lightning liquidity providers.</li>
<li>If you make a payment using Fiat, we may collect X. We will share your payment details with our fiat payment processor Square (Block, Inc.),. - Please see "Information we collect about customers" on Square's website at https://squareup.com/us/en/legal/general/privacy.</li>
<li>If you make a payment using Fiat we will collect your payment details. We will share your payment details with our fiat payment processor Square (Block, Inc.),. - Please see "Information we collect about customers" on Square's website at https://squareup.com/us/en/legal/general/privacy.</li>
</ul>
@@ -5,7 +5,7 @@
ngbTooltip="Miners Reward" placement="bottom" #minersreward [disableTooltip]="!isEllipsisActive(minersreward)">Miners Reward</h5>
<div class="card-text" i18n-ngbTooltip="mining.rewards-desc" ngbTooltip="Amount being paid to miners in the past 144 blocks" placement="bottom">
<div class="fee-text">
<app-amount [satoshis]="rewardStats.totalReward" digitsInfo="1.2-2" [noFiat]="true"></app-amount>
<app-amount [satoshis]="rewardStats.totalReward" digitsInfo="1.2-2" [noFiat]="true" [ignoreViewMode]="true"></app-amount>
</div>
<span class="fiat">
<app-fiat [value]="rewardStats.totalReward" digitsInfo="1.0-0" ></app-fiat>
@@ -47,6 +47,7 @@
<div class="card-title" i18n="search.mining-pools">Mining Pools</div>
<ng-template ngFor [ngForOf]="results.pools" let-pool let-i="index">
<button (click)="clickItem(results.hashQuickMatch + results.addresses.length + i)" [class.active]="results.hashQuickMatch + results.addresses.length + i === activeIdx" [class.inactive]="!pool.active" type="button" role="option" class="dropdown-item">
<img class="pool-logo" [src]="'/resources/mining-pools/' + pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + pool.name + ' mining pool'">
<ngb-highlight [result]="pool.name" [term]="results.searchText"></ngb-highlight>
</button>
</ng-template>
@@ -26,3 +26,11 @@
.active {
background-color: var(--active-bg);
}
.pool-logo {
width: 15px;
height: 15px;
position: relative;
top: -1px;
margin-right: 10px;
}
@@ -33,9 +33,25 @@
<h4>NO ADVERTISING</h4>
<p>Out of respect for the Bitcoin community, this website does not display advertising, and generally does not link to external websites. However, external links may be made for references to Bitcoin's technical documentation in addition to the exceptions detailed below.</p>
<p>We reserve the right to remove any links from our website that in our sole discretion are inappropriate.</p>
<p>Out of respect for the Bitcoin community, this website does not display advertising, and generally does not link to external websites. However, external links are made for references to Bitcoin's technical documentation, for acknowledgements of individual members and open-source projects within the Bitcoin community, and for direct contributors and supporters of <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a>, as follows:</p>
<ul>
<li>In order to refer to Bitcoin technical documentation, external links may by added where applicable, to informational websites that respect that Bitcoin community and do not display advertising, altcoins, or third-party trackers, such as <a href="https://en.bitcoin.it/">bitcoin.it</a> and <a href="https://bitcoin.org/">bitcoin.org</a>.</li>
<br>
<li>In order to acknowledge individual contributors to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> who have made <a href="https://github.com/mempool/mempool/graphs/contributors">at least 5 contributions visible on GitHub</a>, the contributor's GitHub profile photo will automatically be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to their GitHub profile</u>.</li>
<br>
<li>In order to acknowledge members of the Bitcoin community who have made a one-time donation of at least 0.01 BTC to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> on <a href="https://mempool.space/about">mempool.space/about</a>, the Bitcoin community members's Twitter profile photo will automatically be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to their Twitter profile</u>.</li>
<br>
<li>In order to acknowledge members of the Bitcoin community who have or have committed to making recurring donations of at least $100 USD per month to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> through <a href="https://github.com/sponsors/mempool">our GitHub Sponsors program</a> for at least 6 months, the Bitcoin community member's GitHub profile photo will automatically be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to their GitHub profile</u>.</li>
<br>
<li>In order to acknowledge open source projects that benefit the Bitcoin community and have integrated <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> into their software, the open source project's logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the project's GitHub repository</u>.</li>
<br>
<li>In order to acknowledge federations or alliances within the Bitcoin community that have a relationship to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a>, the federation or alliance logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the alliance website</u>.</li>
<br>
<li>In order to acknowledge the enterprise organizations within the Bitcoin community that have or have committed to making recurring donations of at least $1000 USD per month to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> through <a href="https://github.com/sponsors/mempool">our GitHub Sponsors program</a> for at least 25 months, the organization's logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the organization's website</u>.</li>
<br>
<li>In order to acknowledge the enterprise organizations within the Bitcoin community that have made a significant one-time donation of at least $25,000 USD to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a>, the organization's logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the organization's website</u>.</li>
</ul>
<p>However, we reserve the right to remove any links from our website that in our sole discretion are inappropriate. All donations are non-refundable.</p>
<br>
@@ -51,90 +67,38 @@
</ng-container>
<h4>COMMUNITY SPONSORSHIP</h4>
<h4>MEMPOOL ACCELERATOR&trade;</h4>
<p><a href="https://mempool.space/accelerator">Mempool Accelerator&trade;</a> enables members of the Bitcoin community to submit requests for transaction prioritization. </p>
<ul>
<li>All donations to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> including <a href="https://mempool.space/sponsor">community sponsorships</a> are non refundable.</li>
<li>Mempool will use reasonable commercial efforts to relay user acceleration requests to Mempool's mining pool partners, but it is at the discretion of Mempool and Mempool's mining pool partners to accept acceleration requests. </li>
<br>
<li>Each calendar year community sponsors will be issued a coupon code which can be redeemed for Mempool merchandise. Fulfillment is provided by the <a href="https://cypherpunk.store/brands/mempool/">cypherpunk store</a> and coupon codes expire 6 months after issuance.</li>
<br>
<li>In order to acknowledge Bitcoin community members who previously made a one-time donation of at least 0.01 BTC to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> on <a href="https://mempool.space/about">mempool.space/about</a>, the Bitcoin community members's X (fka twitter) profile photo is automatically be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to their X profile</u>.</li>
<br>
<li>In order to acknowledge members of the Bitcoin community who have donated to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> via Chad or Whale <a href="https://mempool.space/sponsor">sponsorships</a>, the Bitcoin community member's X (fka Twitter) profile photo will automatically be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to their X profile</u> while the subscription is active.</li>
<br>
<li>In order to acknowledge the enterprise organizations within the Bitcoin community that have made a significant one-time donation of at least $100,000 USD to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a>, the organization's logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the organization's website</u>.</li>
</ul>
<br>
<h4>MEMPOOL ENTERPRISE™</h4>
<ul>
<li>The full Terms of Service for Mempool Enterprise™ are available upon request. </li>
<br>
<li>All <a href="https://mempool.space/enterprise">Mempool Enterprise™ </a> subscription payments are non refundable.</li>
<br>
<li>In order to acknowledge the enterprise organizations within the Bitcoin community that have subscribed to <a href="https://mempool.space/enterprise">Mempool Enterprise™</a> for at least 25 months, the organization's logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the organization's website</u>.</li>
</ul>
<br>
<h4>MEMPOOL ACCELERATOR™</h4>
<p><a href="https://mempool.space/accelerator">Mempool Accelerator™</a> enables members of the Bitcoin community to submit requests for transaction prioritization to Mempool Mining Partners via mempool.space. </p>
<ul>
<li>All acceleration payments and Mempool Accelerator™ account credit top-ups are non refundable. Mempool Accelerator™ account credit top-ups are prepayment for future accelerations and cannot be withdrawn or transferred.</li>
<br>
<li>Acceleration requests cannot be canceled by the user once submitted. </li>
<br>
<li>Mempool reserves the right to cancel acceleration requests for any reason, including but not limited to the ejection of an accelerated transaction from Mempools mempool. Canceled accelerations will not be refunded.</li>
<li>Mempool reserves the right to cancel acceleration requests for any reason, including but not limited to the ejection of an accelerated transaction from Mempool's mempool. Canceled accelerations will not be refunded.</li>
<br>
<li>All acceleration payments and Mempool Accelerator&trade; account credit top-ups are non-refundable. </li>
<br>
<li>Mempool Accelerator&trade; account credit top-ups are prepayment for future accelerations and cannot be withdrawn or transferred.</li>
<br>
<li>Services are only available to persons in eligible countries, and in our discretion we may not provide Services (or may provide limited services) in one or more countries from time to time or determine that one or more countries are Restricted Jurisdictions. </li>
<br>
<li>It is at the discretion of mempool and mempool accelerator mining pool partners as to whether they choose to accept acceleration requests. </li>
<li>Mempool does not provide acceleration services to persons in Cuba, Iran, North Korea, Russia, Syria, Crimea, Donetsk or Luhansk Regions of Ukraine.</li>
</ul>
<br>
<h4>PARTNERSHIPS AND INTEGRATIONS</h4>
<ul>
<li>In order to acknowledge individual contributors to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> who have made <a href="https://github.com/mempool/mempool/graphs/contributors">at least 5 contributions visible on GitHub</a>, the contributor's GitHub profile photo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to their GitHub profile</u>.</li>
<br>
<li>In order to acknowledge open source projects that benefit the Bitcoin community and have integrated <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a> into their software, the open source project's logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with
a link to the project's <u>GitHub repository</u>.</li>
<br>
<li>In order to acknowledge federations or alliances within the Bitcoin community that have a relationship to <a href="https://github.com/mempool/mempool">The Mempool Open Source Project</a>, the federation or alliance logo may be displayed on <a href="https://mempool.space/about">mempool.space/about</a>, with <u>a link to the alliance website</u>.</li>
</ul>
<p>EOF</p>
</div>
@@ -35,6 +35,7 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
@Input() units: string[] = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'];
@Input() minUnit: 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second' = 'second';
@Input() fractionDigits: number = 0;
@Input() lowercaseStart = false;
constructor(
private ref: ChangeDetectorRef,
@@ -106,6 +107,9 @@ export class TimeComponent implements OnInit, OnChanges, OnDestroy {
return $localize`:@@date-base.immediately:Immediately`;
} else if (seconds < 60) {
if (this.relative || this.kind === 'since') {
if (this.lowercaseStart) {
return $localize`:@@date-base.just-now:Just now`.charAt(0).toLowerCase() + $localize`:@@date-base.just-now:Just now`.slice(1);
}
return $localize`:@@date-base.just-now:Just now`;
} else if (this.kind === 'until' || this.kind === 'within') {
seconds = 60;
@@ -75,9 +75,6 @@
} @else {
<app-time kind="until" [time]="eta.time" [fastRender]="false" [fixedRender]="true"></app-time>
}
<!-- @if (!showAccelerationSummary && isMobile && !tx.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !tx?.acceleration) {
<a class="btn btn-sm accelerate btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
} -->
</span>
</ng-container>
<ng-template #etaSkeleton>
@@ -120,68 +117,71 @@
<div class="spinner-border text-light" style="width: 1em; height: 1em"></div>
</div>
<span class="explainer">&nbsp;</span>
} @else if (showAccelerationSummary) {
<ng-container *ngIf="(ETA$ | async) as eta;">
<app-accelerate-checkout
*ngIf="(da$ | async) as da;"
[cashappEnabled]="cashappEligible"
[advancedEnabled]="false"
[forceMobile]="true"
[tx]="tx"
[accelerating]="isAcceleration"
[miningStats]="miningStats"
[eta]="eta"
[scrollEvent]="scrollIntoAccelPreview"
(unavailable)="eligibleForAcceleration = false"
class="h-100 w-100"
></app-accelerate-checkout>
</ng-container>
} @else {
@if (tx?.acceleration && !tx.status?.confirmed) {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'wand-magic-sparkles']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.accelerated">Your transaction has been accelerated</span>
} @else {
@switch (trackerStage) {
@case ('waiting') {
<div class="progress-icon">
<div class="spinner-border text-light" style="width: 1em; height: 1em"></div>
</div>
<span class="explainer" i18n="tracker.explain.waiting">Waiting for your transaction to appear in the mempool</span>
}
@case ('pending') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'hourglass-start']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.pending">Your transaction is in the mempool, but it will not be confirmed for some time.</span>
}
@case ('soon') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'hourglass-half']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.soon">Your transaction is near the top of the mempool, and is expected to confirm soon.</span>
}
@case ('next') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'hourglass-end']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.next-block">Your transaction is expected to confirm in the next block</span>
}
@case ('confirmed') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'circle-check']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.confirmed">Your transaction is confirmed!</span>
}
@case ('replaced') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'timeline']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.replaced">Your transaction has been replaced by a newer version!</span>
@if (!tx.status?.confirmed && showAccelerationSummary) {
<ng-container *ngIf="(ETA$ | async) as eta;">
<app-accelerate-checkout
*ngIf="(da$ | async) as da;"
[cashappEnabled]="cashappEligible"
[advancedEnabled]="false"
[forceMobile]="true"
[tx]="tx"
[accelerating]="isAcceleration"
[miningStats]="miningStats"
[eta]="eta"
[scrollEvent]="scrollIntoAccelPreview"
(unavailable)="eligibleForAcceleration = false"
class="w-100"
></app-accelerate-checkout>
</ng-container>
}
<div class="status-panel d-flex flex-column h-100 w-100 justify-content-center align-items-center" [class.small-status]="!tx.status?.confirmed && showAccelerationSummary">
@if (tx?.acceleration && !tx.status?.confirmed) {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'wand-magic-sparkles']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.accelerated">Your transaction has been accelerated</span>
} @else {
@switch (trackerStage) {
@case ('waiting') {
<div class="progress-icon">
<div class="spinner-border text-light" style="width: 1em; height: 1em"></div>
</div>
<span class="explainer" i18n="tracker.explain.waiting">Waiting for your transaction to appear in the mempool</span>
}
@case ('pending') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'hourglass-start']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.pending">Your transaction is in the mempool, but it will not be confirmed for some time.</span>
}
@case ('soon') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'hourglass-half']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.soon">Your transaction is near the top of the mempool, and is expected to confirm soon.</span>
}
@case ('next') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'hourglass-end']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.next-block">Your transaction is expected to confirm in the next block</span>
}
@case ('confirmed') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'circle-check']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.confirmed">Your transaction is confirmed!</span>
}
@case ('replaced') {
<div class="progress-icon">
<fa-icon [icon]="['fas', 'timeline']" [fixedWidth]="true"></fa-icon>
</div>
<span class="explainer" i18n="tracker.explain.replaced">Your transaction has been replaced by a newer version!</span>
}
}
}
}
</div>
}
</div>
@@ -166,7 +166,7 @@
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
justify-content: start;
.explainer {
margin: 0 1em;
@@ -178,6 +178,15 @@
font-size: clamp(30px, 20vw, 150px);
}
.status-panel {
&.small-status {
min-height: 180px;
.progress-icon {
font-size: clamp(20px, 13vw, 100px);
}
}
}
.footer-link {
display: flex;
flex-direction: row;
@@ -596,6 +596,9 @@ export class TrackerComponent implements OnInit, OnDestroy {
this.isAccelerated$,
this.txChanged$,
]).pipe(
filter(([position, mempoolBlocks, da, isAccelerated]) => {
return this.tx && !this.tx?.status?.confirmed && position && this.tx.txid === position.txid;
}),
map(([position, mempoolBlocks, da, isAccelerated]) => {
return this.etaService.calculateETA(
this.network,
@@ -728,7 +731,6 @@ export class TrackerComponent implements OnInit, OnDestroy {
if (!this.txId) {
return;
}
this.enterpriseService.goal(8);
this.accelerationFlowCompleted = false;
if (this.showAccelerationSummary) {
this.scrollIntoAccelPreview = true;
@@ -449,7 +449,7 @@
<tr>
<td i18n="block.timestamp">Timestamp</td>
<td>
&lrm;{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}
&lrm;{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm:ss' }}
<div class="lg-inline">
<i class="symbol">(<app-time kind="since" [time]="tx.status.block_time" [fastRender]="true"></app-time>)</i>
</div>
@@ -481,7 +481,7 @@
<td i18n="transaction.first-seen|Transaction first seen">First seen</td>
<td><i><app-time kind="since" [time]="transactionTime" [fastRender]="true" [showTooltip]="true"></app-time></i></td>
</tr>
} @else {
} @else if (isLoadingFirstSeen) {
<tr>
<td i18n="transaction.first-seen|Transaction first seen">First seen</td>
<td><span class="skeleton-loader"></span></td>
@@ -639,7 +639,7 @@
}
<td>
<div class="effective-fee-container">
@if (accelerationInfo?.acceleratedFeeRate && (!tx.effectiveFeePerVsize || accelerationInfo.acceleratedFeeRate >= tx.effectiveFeePerVsize)) {
@if (accelerationInfo?.acceleratedFeeRate && (!tx.effectiveFeePerVsize || accelerationInfo.acceleratedFeeRate >= tx.effectiveFeePerVsize || tx.acceleration)) {
<app-fee-rate [fee]="accelerationInfo.acceleratedFeeRate"></app-fee-rate>
} @else {
<app-fee-rate [fee]="tx.effectiveFeePerVsize"></app-fee-rate>
@@ -663,7 +663,7 @@
<ng-template #acceleratingRow>
<tr>
<td rowspan="2" colspan="2" style="padding: 0;">
<app-active-acceleration-box [tx]="tx" [accelerationInfo]="accelerationInfo" [miningStats]="miningStats" [chartPositionLeft]="isMobile"></app-active-acceleration-box>
<app-active-acceleration-box [tx]="tx" [accelerationInfo]="accelerationInfo" [miningStats]="miningStats" [hasCpfp]="hasCpfp" (toggleCpfp)="showCpfpDetails = !showCpfpDetails" [chartPositionLeft]="isMobile"></app-active-acceleration-box>
</td>
</tr>
<tr></tr>
@@ -42,7 +42,7 @@ interface Pool {
slug: string;
}
interface AuditStatus {
export interface TxAuditStatus {
seen?: boolean;
expected?: boolean;
added?: boolean;
@@ -100,7 +100,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
sigops: number | null;
adjustedVsize: number | null;
pool: Pool | null;
auditStatus: AuditStatus | null;
auditStatus: TxAuditStatus | null;
isAcceleration: boolean = false;
filters: Filter[] = [];
showCpfpDetails = false;
@@ -132,6 +132,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
tooltipPosition: { x: number, y: number };
isMobile: boolean;
firstLoad = true;
waitingForAccelerationInfo: boolean = false;
isLoadingFirstSeen = false;
featuresEnabled: boolean;
segwitEnabled: boolean;
@@ -317,11 +319,19 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.setIsAccelerated();
}),
switchMap((blockHeight: number) => {
return this.servicesApiService.getAccelerationHistory$({ blockHeight });
return this.servicesApiService.getAccelerationHistory$({ blockHeight }).pipe(
switchMap((accelerationHistory: Acceleration[]) => {
if (this.tx.acceleration && !accelerationHistory.length) { // If the just mined transaction was accelerated, but services backend did not return any acceleration data, retry
return throwError('retry');
}
return of(accelerationHistory);
}),
retry({ count: 3, delay: 2000 }),
catchError(() => {
return of([]);
})
);
}),
catchError(() => {
return of([]);
})
).subscribe((accelerationHistory) => {
for (const acceleration of accelerationHistory) {
if (acceleration.txid === this.txId && (acceleration.status === 'completed' || acceleration.status === 'completed_provisional')) {
@@ -330,13 +340,14 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
acceleration.boost = boostCost;
this.tx.acceleratedAt = acceleration.added;
this.accelerationInfo = acceleration;
this.waitingForAccelerationInfo = false;
this.setIsAccelerated();
}
}
});
this.miningSubscription = this.fetchMiningInfo$.pipe(
filter((target) => target.txid === this.txId),
filter((target) => target.txid === this.txId && !this.pool),
tap(() => {
this.pool = null;
}),
@@ -364,33 +375,41 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
const auditAvailable = this.isAuditAvailable(height);
const isCoinbase = this.tx.vin.some(v => v.is_coinbase);
const fetchAudit = auditAvailable && !isCoinbase;
return fetchAudit ? this.apiService.getBlockAudit$(hash).pipe(
map(audit => {
const isAdded = audit.addedTxs.includes(txid);
const isPrioritized = audit.prioritizedTxs.includes(txid);
const isAccelerated = audit.acceleratedTxs.includes(txid);
const isConflict = audit.fullrbfTxs.includes(txid);
const isExpected = audit.template.some(tx => tx.txid === txid);
const firstSeen = audit.template.find(tx => tx.txid === txid)?.time;
return {
seen: isExpected || isPrioritized || isAccelerated,
expected: isExpected,
added: isAdded,
prioritized: isPrioritized,
conflict: isConflict,
accelerated: isAccelerated,
firstSeen,
};
}),
retry({ count: 3, delay: 2000 }),
catchError(() => {
return of(null);
})
) : of(isCoinbase ? { coinbase: true } : null);
if (fetchAudit) {
// If block audit is already cached, use it to get transaction audit
const blockAuditLoaded = this.apiService.getBlockAuditLoaded(hash);
if (blockAuditLoaded) {
return this.apiService.getBlockAudit$(hash).pipe(
map(audit => {
const isAdded = audit.addedTxs.includes(txid);
const isPrioritized = audit.prioritizedTxs.includes(txid);
const isAccelerated = audit.acceleratedTxs.includes(txid);
const isConflict = audit.fullrbfTxs.includes(txid);
const isExpected = audit.template.some(tx => tx.txid === txid);
const firstSeen = audit.template.find(tx => tx.txid === txid)?.time;
return {
seen: isExpected || isPrioritized || isAccelerated,
expected: isExpected,
added: isAdded,
prioritized: isPrioritized,
conflict: isConflict,
accelerated: isAccelerated,
firstSeen,
};
})
)
} else {
return this.apiService.getBlockTxAudit$(hash, txid).pipe(
retry({ count: 3, delay: 2000 }),
catchError(() => {
return of(null);
})
)
}
} else {
return of(isCoinbase ? { coinbase: true } : null);
}
}),
catchError((e) => {
return of(null);
})
).subscribe(auditStatus => {
this.auditStatus = auditStatus;
if (this.auditStatus?.firstSeen) {
@@ -608,12 +627,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.stateService.txConfirmed$.subscribe(([txConfirmed, block]) => {
if (txConfirmed && this.tx && !this.tx.status.confirmed && txConfirmed === this.tx.txid) {
if (this.tx.acceleration) {
this.waitingForAccelerationInfo = true;
}
this.tx.status = {
confirmed: true,
block_height: block.height,
block_hash: block.id,
block_time: block.timestamp,
};
this.pool = block.extras.pool;
this.txChanged$.next(true);
this.stateService.markBlock$.next({ blockHeight: block.height });
if (this.tx.acceleration || (this.accelerationInfo && ['accelerating', 'completed_provisional', 'completed'].includes(this.accelerationInfo.status))) {
@@ -724,7 +747,6 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
document.location.hash = '#accelerate';
this.enterpriseService.goal(8);
this.openAccelerator();
this.scrollIntoAccelPreview = true;
return false;
@@ -742,8 +764,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
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];
@@ -803,7 +833,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
setIsAccelerated(initialState: boolean = false) {
this.isAcceleration = (this.tx.acceleration || (this.accelerationInfo && this.pool && this.accelerationInfo.pools.some(pool => (pool === this.pool.id))));
this.isAcceleration = ((this.tx.acceleration && (!this.tx.status.confirmed || this.waitingForAccelerationInfo)) || (this.accelerationInfo && this.pool && this.accelerationInfo.pools.some(pool => (pool === this.pool.id))));
if (this.isAcceleration) {
if (initialState) {
this.accelerationFlowCompleted = true;
@@ -6,7 +6,7 @@
<app-truncate [text]="tx.txid"></app-truncate>
</a>
<div>
<ng-template [ngIf]="tx.status.confirmed">&lrm;{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm' }}</ng-template>
<ng-template [ngIf]="tx.status.confirmed">&lrm;{{ tx.status.block_time * 1000 | date:'yyyy-MM-dd HH:mm:ss' }}</ng-template>
<ng-template [ngIf]="!tx.status.confirmed && tx.firstSeen">
<i><app-time kind="since" [time]="tx.firstSeen" [fastRender]="true" [showTooltip]="true"></app-time></i>
</ng-template>
+86 -11
View File
@@ -9017,18 +9017,89 @@ export const restApiDocsData = [
"effectiveFee": 154,
"ancestorCount": 1
},
"cost": 3850,
"targetFeeRate": 26,
"nextBlockFee": 4004,
"userBalance": 99900000,
"mempoolBaseFee": 40000,
"vsizeFee": 50000,
"hasAccess": true
"cost": 1386,
"targetFeeRate": 10,
"nextBlockFee": 1540,
"userBalance": 0,
"mempoolBaseFee": 50000,
"vsizeFee": 0,
"pools": [
111,
102,
112,
142,
115
],
"options": [
{
"fee": 1500
},
{
"fee": 3000
},
{
"fee": 12500
}
],
"hasAccess": false,
"availablePaymentMethods": {
"bitcoin": {
"enabled": true,
"min": 1000,
"max": 10000000
},
"cashapp": {
"enabled": true,
"min": 10,
"max": 200
}
},
"unavailable": false
}`,
},
}
}
},
{
options: { officialOnly: true },
type: "endpoint",
category: "accelerator-public",
httpRequestMethod: "POST",
fragment: "accelerator-get-invoice",
title: "POST Generate Acceleration Invoice",
description: {
default: "<p>Request a LN invoice to accelerate a transaction.</p>"
},
urlString: "/v1/services/payments/bitcoin",
showConditions: [""],
showJsExamples: showJsExamplesDefaultFalse,
codeExample: {
default: {
codeTemplate: {
curl: `%{1}" "[[hostname]][[baseNetworkUrl]]/api/v1/services/payments/bitcoin`, //custom interpolation technique handled in replaceCurlPlaceholder()
commonJS: ``,
esModule: ``
},
codeSampleMainnet: {
esModule: [],
commonJS: [],
curl: ["product=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29&amount=12500"],
headers: "",
response: `[
{
"btcpayInvoiceId": "4Ww53d7VgSa596jmCFufe7",
"btcDue": "0.000625",
"addresses": {
"BTC": "bc1qcvqx2kr5mktd7gvym0atrrx0sn27mwv5kkghl3m78kegndm5t8ksvcqpja",
"BTC_LNURLPAY": null,
"BTC_LightningLike": "lnbc625u1pngl0wzpp56j7cqghsw2y5q7vdu9shmpxgpzsx4pqra4wcm9vdnvqegutplk2qdxj2pskjepqw3hjqnt9d4cx7mmvypqkxcm9d3jhyct5daezq2z0wfjx2u3qf9zr5grpvd3k2mr9wfshg6t0dckk2ef3xdjkyc3e8ymrxv3nxumkxvf4vvungwfcxqen2dmxxcmngepj8q6kzce5xyengdfjxq6nqvpnx9jkzdnyvdjrxefevgexgcej8yknzdejxqmrjd3jx5mrgdpj9ycqzpuxqrpr5sp58593dzj2uauaj3afa7x47qeam8k9yyqrh9qasj2ssdzstew6qv3q9qxpqysgqj8qshfkxmj0gfkly5xfydysvsx55uhnc6fgpw66uf6hl8leu07454axe2kq0q788yysg8guel2r36d6f75546nkhmdcmec4mmlft8dsq62rnsj"
}
}
]`,
},
}
}
},
{
options: { officialOnly: true },
type: "endpoint",
@@ -9119,14 +9190,18 @@ export const restApiDocsData = [
"txid": "d7e1796d8eb4a09d4e6c174e36cfd852f1e6e6c9f7df4496339933cd32cbdd1d",
"status": "completed",
"added": 1707421053,
"lastUpdated": 1707422952,
"lastUpdated": 1719134667,
"effectiveFee": 146,
"effectiveVsize": 141,
"feeDelta": 14000,
"blockHash": "00000000000000000000482f0746d62141694b9210a813b97eb8445780a32003",
"blockHeight": 829559,
"bidBoost": 6102,
"pools": [111]
"bidBoost": 3239,
"boostVersion": "v1",
"pools": [
111
],
"minedByPoolUniqueId": 111
}
]`,
},
@@ -9229,7 +9304,7 @@ export const restApiDocsData = [
category: "accelerator-private",
httpRequestMethod: "POST",
fragment: "accelerator-accelerate",
title: "POST Accelerate A Transaction",
title: "POST Accelerate A Transaction (Pro)",
description: {
default: "<p>Sends a request to accelerate a transaction.</p>"
},
@@ -194,7 +194,7 @@
</ng-template>
<ng-template type="how-to-get-transaction-confirmed-quickly">
<p>To get your transaction confirmed quicker, you will need to increase its effective feerate.</p><p>If your transaction was created with RBF enabled, your stuck transaction can simply be replaced with a new one that has a higher fee. Otherwise, if you control any of the stuck transaction's outputs, you can use CPFP to increase your stuck transaction's effective feerate.</p><p>If you are not sure how to do RBF or CPFP, work with the tool you used to make the transaction (wallet software, exchange company, etc).</p><p *ngIf="officialMempoolInstance">Another option to get your transaction confirmed more quickly is Mempool Accelerator™. This service is still in development, but you can <a href="https://mempool.space/accelerator">sign up for the waitlist</a> to be notified when it's ready.</p>
<p>To get your transaction confirmed quicker, you will need to increase its effective feerate.</p><p>If your transaction was created with RBF enabled, your stuck transaction can simply be replaced with a new one that has a higher fee. Otherwise, if you control any of the stuck transaction's outputs, you can use CPFP to increase your stuck transaction's effective feerate.</p><p>If you are not sure how to do RBF or CPFP, work with the tool you used to make the transaction (wallet software, exchange company, etc).</p><p>Another option to get your transaction confirmed more quickly is <a [href]="[ isMempoolSpaceBuild ? '/accelerator' : 'https://mempool.space/accelerator']" [target]="isMempoolSpaceBuild ? '' : 'blank'">Mempool Accelerator™</a>.</p>
</ng-template>
<ng-template type="how-prevent-stuck-transaction">
@@ -33,6 +33,7 @@ export class ApiDocsComponent implements OnInit, AfterViewInit {
showMobileEnterpriseUpsell: boolean = true;
timeLtrSubscription: Subscription;
timeLtr: boolean = this.stateService.timeLtr.value;
isMempoolSpaceBuild = this.stateService.isMempoolSpaceBuild;
@ViewChildren(FaqTemplateDirective) faqTemplates: QueryList<FaqTemplateDirective>;
dict = {};
@@ -50,7 +50,7 @@ const routes: Routes = [
},
{
path: 'acceleration',
data: { networks: ['bitcoin'] },
data: { networks: ['bitcoin'], networkSpecific: true, onlySubnet: [''] },
component: StartComponent,
children: [
{
@@ -61,7 +61,7 @@ const routes: Routes = [
},
{
path: 'acceleration/list/:page',
data: { networks: ['bitcoin'] },
data: { networks: ['bitcoin'], networkSpecific: true, onlySubnet: [''] },
component: AccelerationsListComponent,
},
{
@@ -140,7 +140,7 @@ const routes: Routes = [
},
{
path: 'acceleration/fees',
data: { networks: ['bitcoin'] },
data: { networks: ['bitcoin'], networkSpecific: true, onlySubnet: [''] },
component: AccelerationFeesGraphComponent,
},
{
@@ -411,7 +411,7 @@ export interface Acceleration {
}
export interface AccelerationHistoryParams {
status?: string;
status?: string; // Single status or comma separated list of status
timeframe?: string;
poolUniqueId?: number;
blockHash?: string;
@@ -5,6 +5,7 @@ export type MenuItem = {
i18n: string;
faIcon: IconName;
link: string;
isExternal?: boolean;
};
export type MenuGroup = {
title: string;
@@ -1,6 +1,6 @@
.dashboard-container {
text-align: center;
margin-top: 0.5rem;
margin-top: 18px;
@media (min-width: 992px) {
padding-bottom: 0px;
}
+18
View File
@@ -8,6 +8,7 @@ import { Transaction } from '../interfaces/electrs.interface';
import { Conversion } from './price.service';
import { StorageService } from './storage.service';
import { WebsocketResponse } from '../interfaces/websocket.interface';
import { TxAuditStatus } from '../components/transaction/transaction.component';
@Injectable({
providedIn: 'root'
@@ -17,6 +18,7 @@ export class ApiService {
private apiBasePath: string; // network path is /testnet, etc. or '' for mainnet
private requestCache = new Map<string, { subject: BehaviorSubject<any>, expiry: number }>;
public blockAuditLoaded: { [hash: string]: boolean } = {};
constructor(
private httpClient: HttpClient,
@@ -369,11 +371,18 @@ export class ApiService {
}
getBlockAudit$(hash: string) : Observable<BlockAudit> {
this.setBlockAuditLoaded(hash);
return this.httpClient.get<BlockAudit>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/block/${hash}/audit-summary`
);
}
getBlockTxAudit$(hash: string, txid: string) : Observable<TxAuditStatus> {
return this.httpClient.get<TxAuditStatus>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/block/${hash}/tx/${txid}/audit`
);
}
getBlockAuditScores$(from: number): Observable<AuditScore[]> {
return this.httpClient.get<AuditScore[]>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/audit/scores` +
@@ -526,4 +535,13 @@ export class ApiService {
this.apiBaseUrl + this.apiBasePath + '/api/v1/accelerations/total' + (queryString?.length ? '?' + queryString : '')
);
}
// Cache methods
async setBlockAuditLoaded(hash: string) {
this.blockAuditLoaded[hash] = true;
}
getBlockAuditLoaded(hash) {
return this.blockAuditLoaded[hash];
}
}
@@ -124,6 +124,7 @@ export class CacheService {
resetBlockCache() {
this.blockHashCache = {};
this.blockCache = {};
this.apiService.blockAuditLoaded = {};
this.blockLoading = {};
this.copiesInBlockQueue = {};
this.blockPriorities = [];
@@ -3,6 +3,7 @@ import { Router, NavigationEnd, ActivatedRouteSnapshot } from '@angular/router';
import { BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { StateService } from './state.service';
import { RelativeUrlPipe } from '../shared/pipes/relative-url/relative-url.pipe';
@Injectable({
providedIn: 'root'
@@ -30,15 +31,30 @@ export class NavigationService {
constructor(
private stateService: StateService,
private router: Router,
private relativeUrlPipe: RelativeUrlPipe,
) {
this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
map(() => this.router.routerState.snapshot.root),
).subscribe((state) => {
this.updateSubnetPaths(state);
if (this.enforceSubnetRestrictions(state)) {
this.updateSubnetPaths(state);
}
});
}
enforceSubnetRestrictions(root: ActivatedRouteSnapshot): boolean {
let route = root;
while (route) {
if (route.data.onlySubnet && !route.data.onlySubnet.includes(this.stateService.network)) {
this.router.navigate([this.relativeUrlPipe.transform('')]);
return false;
}
route = route.firstChild;
}
return true;
}
// For each network (bitcoin/liquid), find and save the longest url path compatible with the current route
updateSubnetPaths(root: ActivatedRouteSnapshot): void {
let path = '';
@@ -25,9 +25,6 @@ export interface IUser {
ogRank: number | null;
}
// Todo - move to config.json
const SERVICES_API_PREFIX = `/api/v1/services`;
@Injectable({
providedIn: 'root'
})
@@ -98,7 +95,7 @@ export class ServicesApiServices {
return of(null);
}
return this.httpClient.get<any>(`${SERVICES_API_PREFIX}/account`);
return this.httpClient.get<any>(`${this.stateService.env.SERVICES_API}/account`);
}
getUserMenuGroups$(): Observable<MenuGroup[]> {
@@ -107,7 +104,7 @@ export class ServicesApiServices {
return of(null);
}
return this.httpClient.get<MenuGroup[]>(`${SERVICES_API_PREFIX}/account/menu`);
return this.httpClient.get<MenuGroup[]>(`${this.stateService.env.SERVICES_API}/account/menu`);
}
logout$(): Observable<any> {
@@ -117,59 +114,59 @@ export class ServicesApiServices {
}
localStorage.removeItem('auth');
return this.httpClient.post(`${SERVICES_API_PREFIX}/auth/logout`, {});
return this.httpClient.post(`${this.stateService.env.SERVICES_API}/auth/logout`, {});
}
getJWT$() {
return this.httpClient.get<any>(`${SERVICES_API_PREFIX}/auth/getJWT`);
return this.httpClient.get<any>(`${this.stateService.env.SERVICES_API}/auth/getJWT`);
}
getServicesBackendInfo$(): Observable<IBackendInfo> {
return this.httpClient.get<IBackendInfo>(`${SERVICES_API_PREFIX}/version`);
return this.httpClient.get<IBackendInfo>(`${this.stateService.env.SERVICES_API}/version`);
}
estimate$(txInput: string) {
return this.httpClient.post<any>(`${SERVICES_API_PREFIX}/accelerator/estimate`, { txInput: txInput }, { observe: 'response' });
return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/estimate`, { txInput: txInput }, { observe: 'response' });
}
accelerate$(txInput: string, userBid: number, accelerationUUID: string) {
return this.httpClient.post<any>(`${SERVICES_API_PREFIX}/accelerator/accelerate`, { txInput: txInput, userBid: userBid, accelerationUUID: accelerationUUID });
return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerate`, { txInput: txInput, userBid: userBid, accelerationUUID: accelerationUUID });
}
accelerateWithCashApp$(txInput: string, token: string, cashtag: string, referenceId: string, accelerationUUID: string) {
return this.httpClient.post<any>(`${SERVICES_API_PREFIX}/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 });
}
getAccelerations$(): Observable<Acceleration[]> {
return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations`);
return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations`);
}
getAggregatedAccelerationHistory$(params: AccelerationHistoryParams): Observable<any> {
return this.httpClient.get<any>(`${SERVICES_API_PREFIX}/accelerator/accelerations/history/aggregated`, { params: { ...params }, observe: 'response' });
return this.httpClient.get<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations/history/aggregated`, { params: { ...params }, observe: 'response' });
}
getAccelerationHistory$(params: AccelerationHistoryParams): Observable<Acceleration[]> {
return this.httpClient.get<Acceleration[]>(`${SERVICES_API_PREFIX}/accelerator/accelerations/history`, { params: { ...params } });
return this.httpClient.get<Acceleration[]>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations/history`, { params: { ...params } });
}
getAccelerationHistoryObserveResponse$(params: AccelerationHistoryParams): Observable<any> {
return this.httpClient.get<any>(`${SERVICES_API_PREFIX}/accelerator/accelerations/history`, { params: { ...params }, observe: 'response'});
return this.httpClient.get<any>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations/history`, { params: { ...params }, observe: 'response'});
}
getAccelerationStats$(params: AccelerationHistoryParams): Observable<AccelerationStats> {
return this.httpClient.get<AccelerationStats>(`${SERVICES_API_PREFIX}/accelerator/accelerations/stats`, { params: { ...params } });
return this.httpClient.get<AccelerationStats>(`${this.stateService.env.SERVICES_API}/accelerator/accelerations/stats`, { params: { ...params } });
}
setupSquare$(): Observable<{squareAppId: string, squareLocationId: string}> {
return this.httpClient.get<{squareAppId: string, squareLocationId: string}>(`${SERVICES_API_PREFIX}/square/setup`);
return this.httpClient.get<{squareAppId: string, squareLocationId: string}>(`${this.stateService.env.SERVICES_API}/square/setup`);
}
getFaucetStatus$() {
return this.httpClient.get<{ address?: string, min: number, max: number, code: 'ok' | 'faucet_not_available' | 'faucet_maximum_reached' | 'faucet_too_soon'}>(`${SERVICES_API_PREFIX}/testnet4/faucet/status`, { responseType: 'json' });
return this.httpClient.get<{ address?: string, min: number, max: number, code: 'ok' | 'faucet_not_available' | 'faucet_maximum_reached' | 'faucet_too_soon'}>(`${this.stateService.env.SERVICES_API}/testnet4/faucet/status`, { responseType: 'json' });
}
requestTestnet4Coins$(address: string, sats: number) {
return this.httpClient.get<{txid: string}>(`${SERVICES_API_PREFIX}/testnet4/faucet/request?address=${address}&sats=${sats}`, { responseType: 'json' });
return this.httpClient.get<{txid: string}>(`${this.stateService.env.SERVICES_API}/testnet4/faucet/request?address=${address}&sats=${sats}`, { responseType: 'json' });
}
generateBTCPayAcceleratorInvoice$(txid: string, sats: number): Observable<any> {
@@ -177,14 +174,14 @@ export class ServicesApiServices {
product: txid,
amount: sats,
};
return this.httpClient.post<any>(`${SERVICES_API_PREFIX}/payments/bitcoin`, params);
return this.httpClient.post<any>(`${this.stateService.env.SERVICES_API}/payments/bitcoin`, params);
}
retreiveInvoice$(invoiceId: string): Observable<any[]> {
return this.httpClient.get<any[]>(`${SERVICES_API_PREFIX}/payments/bitcoin/invoice?id=${invoiceId}`);
return this.httpClient.get<any[]>(`${this.stateService.env.SERVICES_API}/payments/bitcoin/invoice?id=${invoiceId}`);
}
getPaymentStatus$(orderId: string): Observable<any[]> {
return this.httpClient.get<any[]>(`${SERVICES_API_PREFIX}/payments/bitcoin/check?order_id=${orderId}`);
getPaymentStatus$(orderId: string): Observable<any> {
return this.httpClient.get<any>(`${this.stateService.env.SERVICES_API}/payments/bitcoin/check?order_id=${orderId}`, { observe: 'response' });
}
}
@@ -75,6 +75,7 @@ export interface Env {
ADDITIONAL_CURRENCIES: boolean;
GIT_COMMIT_HASH_MEMPOOL_SPACE?: string;
PACKAGE_JSON_VERSION_MEMPOOL_SPACE?: string;
SERVICES_API?: string;
customize?: Customization;
}
@@ -109,6 +110,7 @@ const defaultEnv: Env = {
'ACCELERATOR': false,
'PUBLIC_ACCELERATIONS': false,
'ADDITIONAL_CURRENCIES': false,
'SERVICES_API': 'https://mempool.space/api/v1/services',
};
@Injectable({
@@ -6,4 +6,4 @@
</span>
}
<ng-template #lowBalance i18n="accelerator.low-balance">Your balance is too low.<br/>Please <a style="color:#105fb0" href="/services/accelerator/overview">top up your account</a>.</ng-template>
<ng-template #lowBalance i18n="accelerator.low-balance">Your balance is too low.<br/>Please <a class="top-up-link" href="/services/accelerator/overview">top up your account</a>.</ng-template>
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -8,7 +8,7 @@ You can also have the mempool.space team run a highly-performant and highly-avai
### Server Hardware
Mempool v2 is powered by [blockstream/electrs](https://github.com/Blockstream/electrs), which is a beast.
Mempool v3 is powered by [mempool/electrs](https://github.com/mempool/electrs), which is a beast.
I recommend a beefy server:
@@ -64,6 +64,57 @@ location @mempool-api-v1-services-cache-disabled {
expires -1;
}
location @mempool-api-v1-services-cache-disabled-addcors {
proxy_pass $mempoolSpaceServices;
# remove these just in case double proxied
proxy_hide_header Onion-Location;
proxy_hide_header Strict-Transport-Security;
proxy_hide_header Content-Security-Policy;
proxy_hide_header X-Frame-Options;
# remove cache headers from services backend
proxy_hide_header Cache-Control;
proxy_hide_header Expires;
proxy_hide_header Pragma;
# pass these headers to services backend
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# add our own cache headers
add_header 'Pragma' 'no-cache';
add_header 'Cache-Control' 'private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
# generate CORS configuration from origin header
set $cors_methods 'GET, POST, PUT, DELETE, OPTIONS';
set $cors_origin 'https://mempool.space';
set $cors_headers 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With';
set $cors_credentials 'true';
# set CORS for approved hostnames
if ($cors_approved_origin = 'legit')
{
set $cors_methods 'GET, POST, PUT, DELETE, OPTIONS';
set $cors_origin "$http_origin";
set $cors_headers 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With';
set $cors_credentials 'true';
}
# set CORS for approved hostnames
add_header Access-Control-Allow-Methods "$cors_methods" always;
add_header Access-Control-Allow-Origin "$cors_origin" always;
add_header Access-Control-Allow-Headers "$cors_headers" always;
add_header Access-Control-Allow-Credentials "$cors_credentials" always;
proxy_redirect off;
proxy_buffering off;
expires -1;
}
location @mempool-api-v1-services-cache-short {
proxy_pass $mempoolSpaceServices;
proxy_cache services;
@@ -95,6 +146,58 @@ location @mempool-api-v1-services-cache-short {
proxy_cache_valid 200 2s;
}
location @mempool-api-v1-services-cache-short-addcors {
proxy_pass $mempoolSpaceServices;
proxy_cache services;
proxy_redirect off;
# remove these just in case double proxied
proxy_hide_header Onion-Location;
proxy_hide_header Strict-Transport-Security;
proxy_hide_header Content-Security-Policy;
proxy_hide_header X-Frame-Options;
# pass these headers to services backend
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# remove cache headers from services backend
proxy_hide_header Cache-Control;
proxy_hide_header Expires;
proxy_hide_header Pragma;
# generate CORS configuration from origin header
set $cors_methods 'GET, POST, PUT, DELETE, OPTIONS';
set $cors_origin 'https://mempool.space';
set $cors_headers 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With';
set $cors_credentials 'true';
# set CORS for approved hostnames
if ($cors_approved_origin = 'legit')
{
set $cors_methods 'GET, POST, PUT, DELETE, OPTIONS';
set $cors_origin "$http_origin";
set $cors_headers 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With';
set $cors_credentials 'true';
}
# set CORS for approved hostnames
add_header Access-Control-Allow-Methods "$cors_methods" always;
add_header Access-Control-Allow-Origin "$cors_origin" always;
add_header Access-Control-Allow-Headers "$cors_headers" always;
add_header Access-Control-Allow-Credentials "$cors_credentials" always;
# add our own cache headers
add_header 'Pragma' 'public';
add_header 'Cache-Control' 'public';
expires 2s;
# server-side cache validity
proxy_cache_valid 200 2s;
}
location @mempool-api-v1-services-cache-medium {
proxy_pass $mempoolSpaceServices;
proxy_cache services;
+144 -91
View File
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
dependencies = [
"gimli",
]
@@ -19,24 +19,24 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.1.0"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "backtrace"
version = "0.3.69"
version = "0.3.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
dependencies = [
"addr2line",
"cc",
@@ -49,27 +49,27 @@ dependencies = [
[[package]]
name = "bitflags"
version = "2.4.2"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bytemuck"
version = "1.14.3"
version = "1.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
[[package]]
name = "bytes"
version = "1.5.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
[[package]]
name = "cc"
version = "1.0.90"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052"
[[package]]
name = "cfg-if"
@@ -88,12 +88,12 @@ dependencies = [
[[package]]
name = "ctor"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad291aa74992b9b7a7e88c38acbbf6ad7e107f1d90ee8775b7bc1fc3394f485c"
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
dependencies = [
"quote",
"syn 2.0.52",
"syn",
]
[[package]]
@@ -119,15 +119,15 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.28.1"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "hashbrown"
version = "0.14.3"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hermit-abi"
@@ -137,9 +137,9 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "indexmap"
version = "2.2.5"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
@@ -147,31 +147,31 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.153"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "libloading"
version = "0.7.4"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
dependencies = [
"cfg-if",
"winapi",
"windows-targets",
]
[[package]]
name = "log"
version = "0.4.21"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "matchers"
@@ -184,24 +184,24 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.7.1"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "miniz_oxide"
version = "0.7.2"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
dependencies = [
"adler",
]
[[package]]
name = "napi"
version = "2.13.3"
version = "2.16.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd063c93b900149304e3ba96ce5bf210cd4f81ef5eb80ded0d100df3e85a3ac0"
checksum = "a1bd081bbaef43600fd2c5dd4c525b8ecea7dfdacf40ebc674e87851dce6559e"
dependencies = [
"bitflags",
"ctor",
@@ -213,29 +213,29 @@ dependencies = [
[[package]]
name = "napi-build"
version = "2.0.1"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e"
checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a"
[[package]]
name = "napi-derive"
version = "2.13.0"
version = "2.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da1c6a8fa84d549aa8708fcd062372bf8ec6e849de39016ab921067d21bde367"
checksum = "87c3b5d4ab13e20a4bb9d3a1e2f3d4e77eee4a205d0f810abfd226b971dc6ce5"
dependencies = [
"cfg-if",
"convert_case",
"napi-derive-backend",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn",
]
[[package]]
name = "napi-derive-backend"
version = "1.0.52"
version = "1.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20bbc7c69168d06a848f925ec5f0e0997f98e8c8d4f2cc30157f0da51c009e17"
checksum = "96de436a6ab93265beef838f8333c8345438f059df6081fe0ad0b8648ee0c524"
dependencies = [
"convert_case",
"once_cell",
@@ -243,14 +243,14 @@ dependencies = [
"quote",
"regex",
"semver",
"syn 1.0.109",
"syn",
]
[[package]]
name = "napi-sys"
version = "2.2.3"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "166b5ef52a3ab5575047a9fe8d4a030cdd0f63c96f071cd6907674453b07bae3"
checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3"
dependencies = [
"libloading",
]
@@ -277,9 +277,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.32.2"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce"
dependencies = [
"memchr",
]
@@ -298,15 +298,15 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "pin-project-lite"
version = "0.2.13"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "priority-queue"
version = "2.0.2"
version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "509354d8a769e8d0b567d6821b84495c60213162761a732d68ce87c964bd347f"
checksum = "70c501afe3a2e25c9bd219aa56ec1e04cdb3fcdd763055be268778c13fa82c1f"
dependencies = [
"autocfg",
"equivalent",
@@ -315,32 +315,32 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.78"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.35"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.9.6"
version = "1.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff"
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata 0.3.9",
"regex-syntax 0.7.5",
"regex-automata 0.4.7",
"regex-syntax 0.8.4",
]
[[package]]
@@ -354,13 +354,13 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.3.9"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.7.5",
"regex-syntax 0.8.4",
]
[[package]]
@@ -371,21 +371,21 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.7.5"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "rustc-demangle"
version = "0.1.23"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "semver"
version = "1.0.22"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "sharded-slab"
@@ -398,26 +398,15 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.13.1"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "syn"
version = "1.0.109"
version = "2.0.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
dependencies = [
"proc-macro2",
"quote",
@@ -436,9 +425,9 @@ dependencies = [
[[package]]
name = "tokio"
version = "1.36.0"
version = "1.38.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df"
dependencies = [
"backtrace",
"num_cpus",
@@ -464,7 +453,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn",
]
[[package]]
@@ -545,3 +534,67 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff. Show more