diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/00-bug-issue.md similarity index 50% rename from .github/ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE/00-bug-issue.md index 08c50925e..b14e9e691 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/00-bug-issue.md @@ -1,7 +1,14 @@ +--- +name: 🐛 Bug Report +about: Report bugs or other issues to us on GitHub +--- + ### Description @@ -14,11 +21,11 @@ ### Steps to reproduce - + ### Expected behaviour - + ### Actual behaviour @@ -26,7 +33,7 @@ ### Screenshots - + #### Device or machine diff --git a/.github/ISSUE_TEMPLATE/30-feature-request.md b/.github/ISSUE_TEMPLATE/30-feature-request.md new file mode 100644 index 000000000..f3ce5ac75 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/30-feature-request.md @@ -0,0 +1,28 @@ +--- +name: ✨ Feature Request +about: Request a feature or suggest other enhancements 💡 +--- + + + +### Description + + + +### Problem to be solved + + + +### Proposed solution + + + +#### Additional info + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..020170eef --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: 💬 Need help? Chat with us on Matrix + url: https://matrix.to/#/#mempool:bitcoin.kyoto + about: For support requests or general questions + - name: 💬 Need help? Chat with us on Keybase + url: https://keybase.io/team/mempool + about: For support requests or general questions diff --git a/backend/.gitignore b/backend/.gitignore index c4339712c..5476d633c 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,7 +1,10 @@ # See http://help.github.com/ignore-files/ for more about ignoring files. -# production config -mempool-config.json +# production config and external assets +*.json +!mempool-config.sample.json + +icons.json # compiled output /dist diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 6ff103bf1..ea656c1de 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -13,7 +13,8 @@ "INITIAL_BLOCKS_AMOUNT": 8, "MEMPOOL_BLOCKS_AMOUNT": 8, "PRICE_FEED_UPDATE_INTERVAL": 3600, - "USE_SECOND_NODE_FOR_MINFEE": false + "USE_SECOND_NODE_FOR_MINFEE": false, + "EXTERNAL_ASSETS": [] }, "CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/api/bitcoin/bitcoin-api.interface.ts b/backend/src/api/bitcoin/bitcoin-api.interface.ts index ad603835a..e2b9158bb 100644 --- a/backend/src/api/bitcoin/bitcoin-api.interface.ts +++ b/backend/src/api/bitcoin/bitcoin-api.interface.ts @@ -108,7 +108,7 @@ export namespace IBitcoinApi { scriptPubKey: string; // (string) The hex-encoded scriptPubKey generated by the address isscript: boolean; // (boolean) If the key is a script iswitness: boolean; // (boolean) If the address is a witness - witness_version?: boolean; // (numeric, optional) The version number of the witness program + witness_version?: number; // (numeric, optional) The version number of the witness program witness_program: string; // (string, optional) The hex value of the witness program confidential_key?: string; // (string) Elements only unconfidential?: string; // (string) Elements only diff --git a/backend/src/api/liquid/icons.ts b/backend/src/api/liquid/icons.ts new file mode 100644 index 000000000..1c7c658af --- /dev/null +++ b/backend/src/api/liquid/icons.ts @@ -0,0 +1,39 @@ +import * as fs from 'fs'; +import config from '../../config'; +import logger from '../../logger'; + +class Icons { + private static FILE_NAME = './icons.json'; + private iconIds: string[] = []; + private icons: { [assetId: string]: string; } = {}; + + constructor() {} + + public loadIcons() { + if (!fs.existsSync(Icons.FILE_NAME)) { + logger.warn(`${Icons.FILE_NAME} does not exist. No Liquid icons loaded.`); + return; + } + const cacheData = fs.readFileSync(Icons.FILE_NAME, 'utf8'); + this.icons = JSON.parse(cacheData); + + for (const i in this.icons) { + this.iconIds.push(i); + } + logger.debug(`Liquid icons has been loaded.`); + } + + public getIconByAssetId(assetId: string): Buffer | undefined { + const icon = this.icons[assetId]; + if (icon) { + return Buffer.from(icon, 'base64'); + } + } + + public getAllIconIds() { + return this.iconIds; + } + +} + +export default new Icons(); diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts index 6cdfd72e7..b10c216a5 100644 --- a/backend/src/api/statistics.ts +++ b/backend/src/api/statistics.ts @@ -267,8 +267,57 @@ class Statistics { } } - private getQueryForDays(div: number) { - return `SELECT id, added, unconfirmed_transactions, + private getQueryForDaysAvg(div: number, interval: string) { + return `SELECT id, UNIX_TIMESTAMP(added) as added, + CAST(avg(unconfirmed_transactions) as FLOAT) as unconfirmed_transactions, + CAST(avg(tx_per_second) as FLOAT) as tx_per_second, + CAST(avg(vbytes_per_second) as FLOAT) as vbytes_per_second, + CAST(avg(vsize_1) as FLOAT) as vsize_1, + CAST(avg(vsize_2) as FLOAT) as vsize_2, + CAST(avg(vsize_3) as FLOAT) as vsize_3, + CAST(avg(vsize_4) as FLOAT) as vsize_4, + CAST(avg(vsize_5) as FLOAT) as vsize_5, + CAST(avg(vsize_6) as FLOAT) as vsize_6, + CAST(avg(vsize_8) as FLOAT) as vsize_8, + CAST(avg(vsize_10) as FLOAT) as vsize_10, + CAST(avg(vsize_12) as FLOAT) as vsize_12, + CAST(avg(vsize_15) as FLOAT) as vsize_15, + CAST(avg(vsize_20) as FLOAT) as vsize_20, + CAST(avg(vsize_30) as FLOAT) as vsize_30, + CAST(avg(vsize_40) as FLOAT) as vsize_40, + CAST(avg(vsize_50) as FLOAT) as vsize_50, + CAST(avg(vsize_60) as FLOAT) as vsize_60, + CAST(avg(vsize_70) as FLOAT) as vsize_70, + CAST(avg(vsize_80) as FLOAT) as vsize_80, + CAST(avg(vsize_90) as FLOAT) as vsize_90, + CAST(avg(vsize_100) as FLOAT) as vsize_100, + CAST(avg(vsize_125) as FLOAT) as vsize_125, + CAST(avg(vsize_150) as FLOAT) as vsize_150, + CAST(avg(vsize_175) as FLOAT) as vsize_175, + CAST(avg(vsize_200) as FLOAT) as vsize_200, + CAST(avg(vsize_250) as FLOAT) as vsize_250, + CAST(avg(vsize_300) as FLOAT) as vsize_300, + CAST(avg(vsize_350) as FLOAT) as vsize_350, + CAST(avg(vsize_400) as FLOAT) as vsize_400, + CAST(avg(vsize_500) as FLOAT) as vsize_500, + CAST(avg(vsize_600) as FLOAT) as vsize_600, + CAST(avg(vsize_700) as FLOAT) as vsize_700, + CAST(avg(vsize_800) as FLOAT) as vsize_800, + CAST(avg(vsize_900) as FLOAT) as vsize_900, + CAST(avg(vsize_1000) as FLOAT) as vsize_1000, + CAST(avg(vsize_1200) as FLOAT) as vsize_1200, + CAST(avg(vsize_1400) as FLOAT) as vsize_1400, + CAST(avg(vsize_1600) as FLOAT) as vsize_1600, + CAST(avg(vsize_1800) as FLOAT) as vsize_1800, + CAST(avg(vsize_2000) as FLOAT) as vsize_2000 \ + FROM statistics \ + WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \ + GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \ + ORDER BY id DESC;`; + } + + private getQueryForDays(div: number, interval: string) { + return `SELECT id, UNIX_TIMESTAMP(added) as added, unconfirmed_transactions, tx_per_second, vbytes_per_second, vsize_1, @@ -308,13 +357,17 @@ class Statistics { vsize_1400, vsize_1600, vsize_1800, - vsize_2000 FROM statistics GROUP BY UNIX_TIMESTAMP(added) DIV ${div} ORDER BY id DESC LIMIT 480`; + vsize_2000 \ + FROM statistics \ + WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \ + GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \ + ORDER BY id DESC;`; } public async $get(id: number): Promise { try { const connection = await DB.pool.getConnection(); - const query = `SELECT * FROM statistics WHERE id = ?`; + const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE id = ?`; const [rows] = await connection.query(query, [id]); connection.release(); if (rows[0]) { @@ -328,7 +381,7 @@ class Statistics { public async $list2H(): Promise { try { const connection = await DB.pool.getConnection(); - const query = `SELECT * FROM statistics ORDER BY id DESC LIMIT 120`; + const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY id DESC LIMIT 120`; const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -341,7 +394,7 @@ class Statistics { public async $list24H(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(180); + const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY id DESC LIMIT 1440`; const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -354,7 +407,7 @@ class Statistics { public async $list1W(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(1260); + const query = this.getQueryForDaysAvg(600, '1 WEEK'); // 10m interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -367,7 +420,7 @@ class Statistics { public async $list1M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(5040); + const query = this.getQueryForDaysAvg(3600, '1 MONTH'); // 1h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -380,7 +433,7 @@ class Statistics { public async $list3M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(15120); + const query = this.getQueryForDaysAvg(14400, '3 MONTH'); // 4h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -393,7 +446,7 @@ class Statistics { public async $list6M(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(30240); + const query = this.getQueryForDaysAvg(21600, '6 MONTH'); // 6h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -406,7 +459,7 @@ class Statistics { public async $list1Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(60480); + const query = this.getQueryForDays(43200, '1 YEAR'); // 12h interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -419,7 +472,7 @@ class Statistics { public async $list2Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120960); + const query = this.getQueryForDays(86400, "2 YEAR"); // 1d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); @@ -432,7 +485,7 @@ class Statistics { public async $list3Y(): Promise { try { const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(181440); + const query = this.getQueryForDays(86400, "3 YEAR"); // 1d interval const [rows] = await connection.query({ sql: query, timeout: this.queryTimeout }); connection.release(); return this.mapStatisticToOptimizedStatistic(rows); diff --git a/backend/src/config.ts b/backend/src/config.ts index 2addc176a..9513324d8 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -16,6 +16,7 @@ interface IConfig { MEMPOOL_BLOCKS_AMOUNT: number; PRICE_FEED_UPDATE_INTERVAL: number; USE_SECOND_NODE_FOR_MINFEE: boolean; + EXTERNAL_ASSETS: string[]; }; ESPLORA: { REST_API_URL: string; @@ -78,6 +79,7 @@ const defaults: IConfig = { 'MEMPOOL_BLOCKS_AMOUNT': 8, 'PRICE_FEED_UPDATE_INTERVAL': 3600, 'USE_SECOND_NODE_FOR_MINFEE': false, + 'EXTERNAL_ASSETS': [], }, 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', diff --git a/backend/src/index.ts b/backend/src/index.ts index 550f95bf5..78c99f016 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -22,6 +22,8 @@ import loadingIndicators from './api/loading-indicators'; import mempool from './api/mempool'; import elementsParser from './api/liquid/elements-parser'; import databaseMigration from './api/database-migration'; +import syncAssets from './sync-assets'; +import icons from './api/liquid/icons'; class Server { private wss: WebSocket.Server | undefined; @@ -78,6 +80,7 @@ class Server { this.setUpWebsocketHandling(); + await syncAssets.syncAssets(); diskCache.loadMempoolCache(); if (config.DATABASE.ENABLED) { @@ -93,6 +96,10 @@ class Server { statistics.startStatistics(); } + if (config.MEMPOOL.NETWORK === 'liquid') { + icons.loadIcons(); + } + fiatConversion.startService(); this.setUpHttpApiRoutes(); @@ -276,6 +283,13 @@ class Server { ; } + if (config.MEMPOOL.NETWORK === 'liquid') { + this.app + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/icons', routes.getAllLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', routes.getLiquidIcon) + ; + } + if (config.MEMPOOL.NETWORK === 'liquid' && config.DATABASE.ENABLED) { this.app .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', routes.$getElementsPegsByMonth) diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 06cebeae1..53387511f 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -19,6 +19,7 @@ import loadingIndicators from './api/loading-indicators'; import { Common } from './api/common'; import bitcoinClient from './api/bitcoin/bitcoin-client'; import elementsParser from './api/liquid/elements-parser'; +import icons from './api/liquid/icons'; class Routes { constructor() {} @@ -807,6 +808,26 @@ class Routes { : (e.message || 'Error')); } } + + public getLiquidIcon(req: Request, res: Response) { + const result = icons.getIconByAssetId(req.params.assetId); + if (result) { + res.setHeader('content-type', 'image/png'); + res.setHeader('content-length', result.length); + res.send(result); + } else { + res.status(404).send('Asset icon not found'); + } + } + + public getAllLiquidIcon(req: Request, res: Response) { + const result = icons.getAllIconIds(); + if (result) { + res.json(result); + } else { + res.status(404).send('Asset icons not found'); + } + } } export default new Routes(); diff --git a/backend/src/sync-assets.ts b/backend/src/sync-assets.ts new file mode 100644 index 000000000..302196458 --- /dev/null +++ b/backend/src/sync-assets.ts @@ -0,0 +1,32 @@ +import axios from 'axios'; +import * as fs from 'fs'; +const fsPromises = fs.promises; +import config from './config'; +import logger from './logger'; + +const PATH = './'; + +class SyncAssets { + constructor() { } + + public async syncAssets() { + for (const url of config.MEMPOOL.EXTERNAL_ASSETS) { + await this.downloadFile(url); + } + } + + private async downloadFile(url: string) { + const fileName = url.split('/').slice(-1)[0]; + logger.info(`Downloading external asset: ${fileName}...`); + try { + const response = await axios.get(url, { + responseType: 'stream', timeout: 30000 + }); + await fsPromises.writeFile(PATH + fileName, response.data); + } catch (e: any) { + throw new Error(`Failed to download external asset. ` + e); + } + } +} + +export default new SyncAssets(); diff --git a/frontend/cypress/fixtures/mainnet_rbf.json b/frontend/cypress/fixtures/mainnet_rbf.json new file mode 100644 index 000000000..50dbbb2df --- /dev/null +++ b/frontend/cypress/fixtures/mainnet_rbf.json @@ -0,0 +1,52 @@ +{ + "rbfTransaction": { + "txid": "8913ec7ba0ede285dbd120e46f6d61a28f2903c10814a6f6c4f97d0edf3e1f46", + "version": 2, + "locktime": 632699, + "vin": [ + { + "txid": "02238126a63ea2669c5f378012180ef8b54402a949316f9b2f1352c51730a086", + "vout": 0, + "prevout": { + "scriptpubkey": "a914f8e495456956c833e5e8c69b9a9dc041aa14c72f87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 f8e495456956c833e5e8c69b9a9dc041aa14c72f OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "3QP3LMD8veT5GtWV83Nosif2Bhr73857VB", + "value": 25000000 + }, + "scriptsig": "22002043288fbbc0fc5efa86c229dbb7d88ab78d57957c65b5d5ceaece70838976ad1b", + "scriptsig_asm": "OP_PUSHBYTES_34 002043288fbbc0fc5efa86c229dbb7d88ab78d57957c65b5d5ceaece70838976ad1b", + "witness": [ + "", + "3044022009e2d3a8e645f65bc89c8492cd9c08e6fb02609fd402214884a754a1970145340220575bb325429def59f3a3f1e22d9740a3feecbe97438ff3bb5796b2c46b3c477f01", + "3044022039c34372882da8fc1c1243bd72b5e7e5e6870301ef56bdebb87bc647fb50f9b5022071a704ee77d742f78b10e45be675d4c45a5f31e884139e75c975144fde70e41701", + "522102346eb7133f11e0dc279bc592d5ac948a91676372a6144c9ae2085625d7fbf70421021b9508a458f9d59be4eb8cc87ad582c3b494106fb1d4ec22801569be0700eb7b52ae" + ], + "is_coinbase": false, + "sequence": 4294967293, + "inner_redeemscript_asm": "OP_0 OP_PUSHBYTES_32 43288fbbc0fc5efa86c229dbb7d88ab78d57957c65b5d5ceaece70838976ad1b", + "inner_witnessscript_asm": "OP_PUSHNUM_2 OP_PUSHBYTES_33 02346eb7133f11e0dc279bc592d5ac948a91676372a6144c9ae2085625d7fbf704 OP_PUSHBYTES_33 021b9508a458f9d59be4eb8cc87ad582c3b494106fb1d4ec22801569be0700eb7b OP_PUSHNUM_2 OP_CHECKMULTISIG" + } + ], + "vout": [ + { + "scriptpubkey": "a914fd4e5e59dd5cf2dc48eaedf1a2a1650ca1ce9d7f87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 fd4e5e59dd5cf2dc48eaedf1a2a1650ca1ce9d7f OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "3QnNmDhZS7toHA7bhhbTPBdtpLJoeecq5c", + "value": 13986350 + }, + { + "scriptpubkey": "76a914edc93d0446deec1c2d514f3a490f050096e74e0e88ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 edc93d0446deec1c2d514f3a490f050096e74e0e OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1NgJDkTUqJxxCAAZrrsC87kWag5kphrRtM", + "value": 11000000 + } + ], + "size": 372, + "weight": 828, + "fee": 1.5, + "status": { "confirmed": false } + } +} \ No newline at end of file diff --git a/frontend/cypress/integration/bisq/bisq.spec.ts b/frontend/cypress/integration/bisq/bisq.spec.ts index 0271ca775..3cea27781 100644 --- a/frontend/cypress/integration/bisq/bisq.spec.ts +++ b/frontend/cypress/integration/bisq/bisq.spec.ts @@ -59,9 +59,8 @@ describe('Bisq', () => { cy.visit(`${basePath}`); cy.waitForSkeletonGone(); cy.get('li:nth-of-type(5) > a').click().then(() => { - cy.get('.card').should('have.length.at.least', 1); - cy.get('.card').first().click(); - cy.get('.card-body'); + cy.get('.section-header').should('have.length.at.least', 1); + cy.get('.endpoint-container').should('have.length.at.least', 1); }); }); diff --git a/frontend/cypress/integration/liquid/liquid.spec.ts b/frontend/cypress/integration/liquid/liquid.spec.ts index 0c9a71f85..26885330b 100644 --- a/frontend/cypress/integration/liquid/liquid.spec.ts +++ b/frontend/cypress/integration/liquid/liquid.spec.ts @@ -62,6 +62,20 @@ describe('Liquid', () => { }); }); + it('renders unconfidential addresses correctly on mobile', () => { + cy.viewport('iphone-6'); + cy.visit(`${basePath}/address/ex1qqmmjdwrlg59c8q4l75sj6wedjx57tj5grt8pat`); + cy.waitForSkeletonGone(); + //TODO: Add proper IDs for these selectors + const firstRowSelector = '.container-xl > :nth-child(3) > div > :nth-child(1) > .table > tbody'; + const thirdRowSelector = '.container-xl > :nth-child(3) > div > :nth-child(3)'; + cy.get(firstRowSelector).invoke('css', 'width').then(firstRowWidth => { + cy.get(thirdRowSelector).invoke('css', 'width').then(thirdRowWidth => { + expect(parseInt(firstRowWidth)).to.be.lessThan(parseInt(thirdRowWidth)); + }); + }); + }); + describe('peg in/peg out', () => { it('loads peg in addresses', () => { cy.visit(`${basePath}/tx/fe764f7bedfc2a37b29d9c8aef67d64a57d253a6b11c5a55555cfd5826483a58`); diff --git a/frontend/cypress/integration/mainnet/mainnet.spec.ts b/frontend/cypress/integration/mainnet/mainnet.spec.ts index 679ba59de..461f5c0a8 100644 --- a/frontend/cypress/integration/mainnet/mainnet.spec.ts +++ b/frontend/cypress/integration/mainnet/mainnet.spec.ts @@ -2,6 +2,36 @@ import { emitMempoolInfo, dropWebSocket } from "../../support/websocket"; const baseModule = Cypress.env("BASE_MODULE"); + +//Credit: https://github.com/bahmutov/cypress-examples/blob/6cedb17f83a3bb03ded13cf1d6a3f0656ca2cdf5/docs/recipes/overlapping-elements.md + +/** + * Returns true if two DOM rectangles are overlapping + * @param {DOMRect} rect1 the bounding client rectangle of the first element + * @param {DOMRect} rect2 the bounding client rectangle of the second element + * @returns {boolean} +*/ +const areOverlapping = (rect1, rect2) => { + // if one rectangle is on the left side of the other + if (rect1.right < rect2.left || rect2.right < rect1.left) { + return false + } + + // if one rectangle is above the other + if (rect1.bottom < rect2.top || rect2.bottom < rect1.top) { + return false + } + + // the rectangles must overlap + return true +} + +/** + * Returns the bounding rectangle of the first DOM + * element in the given jQuery object. + */ +const getRectangle = ($el) => $el[0].getBoundingClientRect(); + describe('Mainnet', () => { beforeEach(() => { //cy.intercept('/sockjs-node/info*').as('socket'); @@ -56,7 +86,7 @@ describe('Mainnet', () => { cy.get('.badge', {timeout: 25000}).should('not.exist'); emitMempoolInfo({ 'params': { - loaded: true + command: 'init' } }); cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist'); @@ -283,7 +313,7 @@ describe('Mainnet', () => { emitMempoolInfo({ 'params': { - loaded: true + command: 'init' } }); @@ -428,6 +458,78 @@ describe('Mainnet', () => { cy.get('.pagination-container ul.pagination').first().children().should('have.length', 7); }); }); + + describe('RBF transactions', () => { + it('shows RBF transactions properly (mobile)', () => { + cy.viewport('iphone-xr'); + cy.mockMempoolSocket(); + cy.visit('/tx/f81a08699b62b2070ad8fe0f2a076f8bea0386a2fdcd8124caee42cbc564a0d5'); + + cy.waitForSkeletonGone(); + + emitMempoolInfo({ + 'params': { + command: 'init' + } + }); + + cy.get('#mempool-block-0'); + + emitMempoolInfo({ + 'params': { + command: 'rbfTransaction' + } + }); + + cy.get('.alert-mempool').should('be.visible'); + cy.get('.alert-mempool').invoke('css', 'width').then((alertWidth) => { + cy.get('.container-xl > :nth-child(3)').invoke('css', 'width').should('equal', alertWidth); + }); + + cy.get('.btn-success').then(getRectangle).then((rectA) => { + cy.get('.alert-mempool').then(getRectangle).then((rectB) => { + expect(areOverlapping(rectA, rectB), 'Confirmations box and RBF alert are overlapping').to.be.false; + }); + }); + }); + + it('shows RBF transactions properly (desktop)', () => { + cy.viewport('macbook-16'); + cy.mockMempoolSocket(); + cy.visit('/tx/f81a08699b62b2070ad8fe0f2a076f8bea0386a2fdcd8124caee42cbc564a0d5'); + + cy.waitForSkeletonGone(); + + emitMempoolInfo({ + 'params': { + command: 'init' + } + }); + + cy.get('#mempool-block-0'); + + emitMempoolInfo({ + 'params': { + command: 'rbfTransaction' + } + }); + + cy.get('.alert-mempool').should('be.visible'); + + const alertLocator = '.alert-mempool'; + const tableLocator = '.container-xl > :nth-child(3)'; + + cy.get(tableLocator).invoke('css', 'width').then((firstWidth) => { + cy.get(alertLocator).invoke('css', 'width').should('equal', firstWidth); + }); + + cy.get('.btn-success').then(getRectangle).then((rectA) => { + cy.get('.alert-mempool').then(getRectangle).then((rectB) => { + expect(areOverlapping(rectA, rectB), 'Confirmations box and RBF alert are overlapping').to.be.false; + }); + }); + }); + }); } else { it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); } diff --git a/frontend/cypress/support/websocket.ts b/frontend/cypress/support/websocket.ts index 03f4a54f1..4a411eeb2 100644 --- a/frontend/cypress/support/websocket.ts +++ b/frontend/cypress/support/websocket.ts @@ -31,19 +31,19 @@ export const mockWebSocket = () => { cy.on('window:before:load', (win) => { const winWebSocket = win.WebSocket; cy.stub(win, 'WebSocket').callsFake((url) => { - console.log(url); + console.log(url); if ((new URL(url).pathname.indexOf('/sockjs-node/') !== 0)) { const { server, websocket } = createMock(url); win.mockServer = server; win.mockServer.on('connection', (socket) => { win.mockSocket = socket; - win.mockSocket.send('{"action":"init"}'); + win.mockSocket.send('{"action":"init"}'); }); - win.mockServer.on('message', (message) => { - console.log(message); - }); + win.mockServer.on('message', (message) => { + console.log(message); + }); return websocket; } else { @@ -68,7 +68,13 @@ export const emitMempoolInfo = ({ //TODO: Use network specific mocks case "signet": case "testnet": + case "mainnet": default: + break; + } + + switch (params.command) { + case "init": { win.mockSocket.send('{"action":"init"}'); win.mockSocket.send('{"action":"want","data":["blocks","stats","mempool-blocks","live-2h-chart"]}'); win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}'); @@ -78,6 +84,16 @@ export const emitMempoolInfo = ({ cy.readFile('cypress/fixtures/mainnet_mempoolInfo.json', 'ascii').then((fixture) => { win.mockSocket.send(JSON.stringify(fixture)); }); + break; + } + case "rbfTransaction": { + cy.readFile('cypress/fixtures/mainnet_rbf.json', 'ascii').then((fixture) => { + win.mockSocket.send(JSON.stringify(fixture)); + }); + break; + } + default: + break; } }); cy.waitForSkeletonGone(); @@ -89,4 +105,4 @@ export const dropWebSocket = (() => { win.mockServer.simulate("error"); }); return cy.wait(500); -}); \ No newline at end of file +}); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 717134fca..8aa1c675e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -26,7 +26,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/free-solid-svg-icons": "^5.15.3", "@juggle/resize-observer": "^3.3.1", - "@mempool/mempool.js": "^2.2.4", + "@mempool/mempool.js": "2.3.0-dev1", "@ng-bootstrap/ng-bootstrap": "^10.0.0", "@nguniversal/express-engine": "11.2.1", "@types/qrcode": "1.4.1", @@ -3230,12 +3230,40 @@ "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==" }, "node_modules/@mempool/mempool.js": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@mempool/mempool.js/-/mempool.js-2.2.4.tgz", - "integrity": "sha512-G9Ga2jHLfAuU/qXikRBtTecYr7BhLJH1WbIahefnGpgP48DCQaj1jizvuRZHhoElUvUT5flRt/O9kLjlbToqhw==", + "version": "2.3.0-dev1", + "resolved": "https://registry.npmjs.org/@mempool/mempool.js/-/mempool.js-2.3.0-dev1.tgz", + "integrity": "sha512-+UYGuG8qqdgrtC4J94hCs7+Dry8OprIixEarIC6rww1Nb5POz8n3NTDH8to1r0XLjPr+Du6/OX8fEN1QW94rNA==", "dependencies": { - "axios": "^0.21.1", - "ws": "^7.4.3" + "axios": "0.24.0", + "ws": "8.3.0" + } + }, + "node_modules/@mempool/mempool.js/node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, + "node_modules/@mempool/mempool.js/node_modules/ws": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz", + "integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@ng-bootstrap/ng-bootstrap": { @@ -4541,6 +4569,7 @@ "version": "0.21.4", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "devOptional": true, "dependencies": { "follow-redirects": "^1.14.0" } @@ -7264,7 +7293,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.3.1" } @@ -9122,7 +9151,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "devOptional": true, + "dev": true, "engines": { "node": ">=4" } @@ -9131,7 +9160,7 @@ "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "devOptional": true, + "dev": true, "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -9416,7 +9445,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "devOptional": true, + "dev": true, "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -10385,7 +10414,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "devOptional": true + "dev": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -10453,7 +10482,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "devOptional": true, + "dev": true, "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -17962,6 +17991,7 @@ "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "devOptional": true, "engines": { "node": ">=8.3.0" } @@ -20409,12 +20439,28 @@ "integrity": "sha512-zMM9Ds+SawiUkakS7y94Ymqx+S0ORzpG3frZirN3l+UlXUmSUR7hF4wxCVqW+ei94JzV5kt0uXBcoOEAuiydrw==" }, "@mempool/mempool.js": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@mempool/mempool.js/-/mempool.js-2.2.4.tgz", - "integrity": "sha512-G9Ga2jHLfAuU/qXikRBtTecYr7BhLJH1WbIahefnGpgP48DCQaj1jizvuRZHhoElUvUT5flRt/O9kLjlbToqhw==", + "version": "2.3.0-dev1", + "resolved": "https://registry.npmjs.org/@mempool/mempool.js/-/mempool.js-2.3.0-dev1.tgz", + "integrity": "sha512-+UYGuG8qqdgrtC4J94hCs7+Dry8OprIixEarIC6rww1Nb5POz8n3NTDH8to1r0XLjPr+Du6/OX8fEN1QW94rNA==", "requires": { - "axios": "^0.21.1", - "ws": "^7.4.3" + "axios": "0.24.0", + "ws": "8.3.0" + }, + "dependencies": { + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + }, + "ws": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz", + "integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==", + "requires": {} + } } }, "@ng-bootstrap/ng-bootstrap": { @@ -21532,6 +21578,7 @@ "version": "0.21.4", "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "devOptional": true, "requires": { "follow-redirects": "^1.14.0" } @@ -23795,7 +23842,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true + "dev": true }, "diffie-hellman": { "version": "5.0.3", @@ -25290,13 +25337,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "devOptional": true + "dev": true }, "har-validator": { "version": "5.1.5", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "devOptional": true, + "dev": true, "requires": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -25544,7 +25591,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "devOptional": true, + "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -26286,7 +26333,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "devOptional": true + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -26339,7 +26386,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "devOptional": true, + "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -32158,7 +32205,8 @@ "ws": { "version": "7.4.6", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "devOptional": true }, "xhr2": { "version": "0.2.0", diff --git a/frontend/package.json b/frontend/package.json index 91f7f3682..f25f8bc32 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,7 +34,10 @@ "sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources", "sync-assets-dev": "node sync-assets.js dev", "generate-config": "node generate-config.js", - "build-mempool.js": "tsc | browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index.js --standalone mempoolJS > ./dist/mempool/browser/en-US/mempool.js", + "build-mempool.js": "npm run build-mempool-js && npm run build-mempool-liquid-js && npm run build-mempool-bisq-js", + "build-mempool-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index.js --standalone mempoolJS > ./dist/mempool/browser/en-US/mempool.js", + "build-mempool-bisq-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index-bisq.js --standalone bisqJS > ./dist/mempool/browser/en-US/bisq.js", + "build-mempool-liquid-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index-liquid.js --standalone liquidJS > ./dist/mempool/browser/en-US/liquid.js", "test": "ng test", "lint": "ng lint", "e2e": "npm run generate-config && ng e2e", @@ -70,7 +73,7 @@ "@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/free-solid-svg-icons": "^5.15.3", "@juggle/resize-observer": "^3.3.1", - "@mempool/mempool.js": "^2.2.4", + "@mempool/mempool.js": "2.3.0-dev1", "@ng-bootstrap/ng-bootstrap": "^10.0.0", "@nguniversal/express-engine": "11.2.1", "@types/qrcode": "1.4.1", diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 0b7c072f6..d6adebbf1 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -48,9 +48,10 @@ import { FeesBoxComponent } from './components/fees-box/fees-box.component'; import { DashboardComponent } from './dashboard/dashboard.component'; import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle, - faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook } from '@fortawesome/free-solid-svg-icons'; + faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl } from '@fortawesome/free-solid-svg-icons'; import { ApiDocsComponent } from './components/docs/api-docs.component'; import { DocsComponent } from './components/docs/docs.component'; +import { ApiDocsNavComponent } from './components/docs/api-docs-nav.component'; import { CodeTemplateComponent } from './components/docs/code-template.component'; import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component'; import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component'; @@ -59,6 +60,7 @@ import { StorageService } from './services/storage.service'; import { HttpCacheInterceptor } from './services/http-cache.interceptor'; import { SponsorComponent } from './components/sponsor/sponsor.component'; import { PushTransactionComponent } from './components/push-transaction/push-transaction.component'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; @NgModule({ declarations: [ @@ -102,6 +104,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra SponsorComponent, PushTransactionComponent, DocsComponent, + ApiDocsNavComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), @@ -111,6 +114,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra BrowserAnimationsModule, InfiniteScrollModule, NgbTypeaheadModule, + NgbModule, FontAwesomeModule, SharedModule, NgxEchartsModule.forRoot({ @@ -161,5 +165,6 @@ export class AppModule { library.addIcons(faAngleRight); library.addIcons(faAngleLeft); library.addIcons(faBook); + library.addIcons(faListUl); } } diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 1728c93e9..f925ad052 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -23,12 +23,12 @@ - - - + + +
@@ -54,6 +54,10 @@ Unchained + + + Blockstream +
@@ -174,7 +178,7 @@
-

Project Staff

+

Project Members

diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index 9d02cf124..c61680ff4 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -21,7 +21,10 @@ Unconfidential - {{ addressInfo.unconfidential }} + + {{ addressInfo.unconfidential | shortenString : 14 }} + {{ addressInfo.unconfidential }} + diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 5e160a90b..1a3942df1 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -1,7 +1,8 @@
-   +   diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index 569f464a5..3b1347cea 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -15,6 +15,10 @@ text-decoration: none; } +.blockLink.disabled { + pointer-events: none; +} + .mined-block { position: absolute; top: 0px; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 3dcac5b78..281081876 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -41,7 +41,7 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { }; constructor( - private stateService: StateService, + public stateService: StateService, private router: Router, private cd: ChangeDetectorRef, ) { } diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index efbdb31ef..fc71bd202 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -18,6 +18,11 @@ .blockchain-wrapper { overflow: hidden; height: 250px; + + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+/Edge */ + user-select: none; /* Standard */ } .position-container { diff --git a/frontend/src/app/components/clipboard/clipboard.component.scss b/frontend/src/app/components/clipboard/clipboard.component.scss index e69de29bb..9483fef52 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.scss +++ b/frontend/src/app/components/clipboard/clipboard.component.scss @@ -0,0 +1,3 @@ +.btn-link { + padding: 0.25rem 0 0.1rem 0.5rem; +} diff --git a/frontend/src/app/components/docs/api-docs-nav.component.html b/frontend/src/app/components/docs/api-docs-nav.component.html new file mode 100644 index 000000000..63ed8d4e1 --- /dev/null +++ b/frontend/src/app/components/docs/api-docs-nav.component.html @@ -0,0 +1,76 @@ + +

General

+ GET Difficulty Adjustment +
+ + +

Markets

+ GET Market Currencies + GET Market Depth + GET Market HLOC + GET Markets + GET Market Offers + GET Market Ticker + GET Market Trades + GET Market Volumes +
+ + +

General

+ GET Stats +
+ +

Addresses

+GET Address +GET Address Transactions +GET Address Transactions Chain +GET Address Transactions Mempool +GET Address UTXO + + +

Assets

+ GET Assets + GET Assets Icons + GET Asset Transactions + GET Asset Supply + GET Asset Icon +
+ +

Blocks

+GET Block +GET Block Header +GET Block Height +GET Block Raw +GET Block Status +GET Block Tip Height +GET Block Tip Hash +GET Block Transaction ID +GET Block Transaction IDs +GET Block Transactions +GET Blocks + + +

Fees

+ GET Mempool Blocks Fees + GET Recommended Fees +
+ + +

Mempool

+ GET Mempool + GET Mempool Transaction IDs + GET Mempool Recent +
+ +

Transactions

+GET Children Pay for Parent +GET Transaction +GET Transaction Hex +GET Transaction Merkleblock Proof +GET Transaction Merkle Proof +GET Transaction Outspend +GET Transaction Outspends +GET Transaction Raw +GET Transaction Status +GET Transactions +POST Transaction diff --git a/frontend/src/app/components/docs/api-docs-nav.component.scss b/frontend/src/app/components/docs/api-docs-nav.component.scss new file mode 100644 index 000000000..225209275 --- /dev/null +++ b/frontend/src/app/components/docs/api-docs-nav.component.scss @@ -0,0 +1,17 @@ +p { + color: #4a68b9; + font-weight: 700; + margin: 10px 0; + margin: 15px 0 10px 0; +} + +p:first-child { + margin-top: 0 +} + +a { + color: #fff; + text-decoration: none; + display: block; + margin: 5px 0; +} diff --git a/frontend/src/app/components/docs/api-docs-nav.component.ts b/frontend/src/app/components/docs/api-docs-nav.component.ts new file mode 100644 index 000000000..5109e2dc0 --- /dev/null +++ b/frontend/src/app/components/docs/api-docs-nav.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'app-api-docs-nav', + templateUrl: './api-docs-nav.component.html', + styleUrls: ['./api-docs-nav.component.scss'] +}) +export class ApiDocsNavComponent implements OnInit { + + @Input() network: any; + @Input() collapseItem: any = { toggle: () => {} }; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/frontend/src/app/components/docs/api-docs.component.html b/frontend/src/app/components/docs/api-docs.component.html index d683676b5..c41bc57c7 100644 --- a/frontend/src/app/components/docs/api-docs.component.html +++ b/frontend/src/app/components/docs/api-docs.component.html @@ -3,261 +3,212 @@
-

Reference for the {{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} API service.

- -
-

General

- - - - - GET Difficulty Adjustment - - -
- -
-
Description
-
Returns details about difficulty adjustment.
-
- -
-
-
- -
+
+
-
-

Markets

- +
- - - GET Market Currencies - - - -
-
Description
-
Provides list of available currencies for a given base currency.
-
- -
-
+

Reference for the {{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} API service.

- - - GET Market Depth - - -
-
Endpoint
- GET {{ baseNetworkUrl }}/api/depth?market=[:market] +
+ +
+
+
+
-
-
Description
-
Provides list of open offer prices for a single market.
-
- - - +
+
+
- - - GET Market HLOC - - - -
-
Description
-
Provides hi/low/open/close data for a given market. This can be used to generate a candlestick chart.
-
- -
-
+
- - - GET Markets - - - -
-
Description
-
Provides list of available markets.
-
- -
-
+
- - - GET Market Offers - - - -
-
Description
-
Provides list of open offer details for a single market.
-
- -
-
+
+ GET Difficulty Adjustment General + +
+
Description
+
Returns details about difficulty adjustment.
+
+ +
- - - GET Market Ticker - - - -
-
Description
-
Provides 24 hour price ticker for single market or all markets
-
- -
-
+
- - - GET Market Trades - - - -
-
Description
-
Provides list of completed trades for a single market.
-
- -
-
+
- - - GET Market Volumes - - - -
-
Description
-
Provides periodic volume data in terms of base currency for one or all markets.
-
- -
-
+
+ GET Market Currencies Markets + +
+
Description
+
Provides list of available currencies for a given base currency.
+
+ +
- -
+
+ GET Market Depth Markets + +
+
Description
+
Provides list of open offer prices for a single market.
+
+ +
-
-

General

- +
+ GET Market HLOC Markets + +
+
Description
+
Provides hi/low/open/close data for a given market. This can be used to generate a candlestick chart.
+
+ +
- - - GET Stats - - - -
-
Description
-
Returns statistics about all Bisq transactions.
-
- -
-
+
+ GET Markets Markets + +
+
Description
+
Provides list of available markets.
+
+ +
-
-
+
+ GET Market Offers Markets + +
+
Description
+
Provides list of open offer details for a single market.
+
+ +
-
-

Addresses

- +
+ GET Market Ticker Markets + +
+
Description
+
Provides 24 hour price ticker for single market or all markets
+
+ +
- - - GET Address - - - -
-
Description
-
Returns details about an address. Available fields: address, chain_stats, and mempool_stats. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum.
-
- -
-
+
+ GET Market Trades Markets + +
+
Description
+
Provides list of completed trades for a single market.
+
+ +
- - - GET Address Transactions - - - -
-
Description
-
Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid (see below).
-
- -
-
+
+ GET Market Volumes Markets + +
+
Description
+
Provides periodic volume data in terms of base currency for one or all markets.
+
+ +
- - - GET Address Transactions Chain - - - -
-
Description
-
Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.
-
- -
-
+
- - - GET Address Transactions Mempool - - +
+ +
+ GET Stats General + +
+
Description
+
Returns statistics about all Bisq transactions.
+
+ +
+ +
+ +
+ +
+ GET Address Addresses + +
+
Description
+
Returns details about an address. Available fields: address, chain_stats, and mempool_stats. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum.
+
+ +
+ +
+ GET Address Transactions Addresses + +
+
Description
+
Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid (see below).
+
+ +
+ +
+ GET Address Transactions Chain Addresses + +
+
Description
+
Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.
+
+ +
+ +
+ GET Address Transactions Mempool Addresses
Endpoint
GET {{ baseNetworkUrl }}/api/address/:address/txs/mempool @@ -267,588 +218,470 @@
Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).
- - +
- - - GET Address UTXO - - - -
-
Description
-
Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof.
-
- -
-
+
+ GET Address UTXO Addresses + +
+
Description
+
Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof.
+
+ +
- -
+
-
-

Assets

- +
- - - GET Assets - - - -
-
Description
-
Returns information about a Liquid asset.
-
- -
-
+
+ GET Assets Assets + +
+
Description
+
Returns information about a Liquid asset.
+
+ +
- - - GET Asset Transactions - - - -
-
Description
-
Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.
-
- -
-
+
+ GET Asset Transactions Assets + +
+
Description
+
Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.
+
+ +
- - - GET Asset Supply - - - -
-
Description
-
Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.
-
- -
-
+
+ GET Asset Supply Assets + +
+
Description
+
Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.
+
+ +
- -
+
+ GET Asset Icons Assets + +
+
Description
+
Get all the Asset IDs that has icons.
+
+ +
-
-

Blocks

- +
+ GET Asset Icon Assets + +
+
Description
+
Get the icon of the specified asset.
+
+ +
- - - GET Block - - - -
-
Description
-
Returns details about a block. Available fields: id, height, version, timestamp, bits, nonce, merkle_root, tx_count, size, weight, proof, and previousblockhash.
-
- -
-
+
- - - GET Block Header - - - -
-
Description
-
Returns the hex-encoded block header.
-
- -
-
+
- - - GET Block Height - - - -
-
Description
-
Returns the hash of the block currently at :height.
-
- -
-
+
+ GET Block Blocks + +
+
Description
+
Returns details about a block. Available fields: id, height, version, timestamp, bits, nonce, merkle_root, tx_count, size, weight, proof, and previousblockhash.
+
+ +
- - - GET Block Raw - - - -
-
Description
-
Returns the raw block representation in binary.
-
- -
-
+
+ GET Block Header Blocks + +
+
Description
+
Returns the hex-encoded block header.
+
+ +
- - - GET Block Status - - -
Get Block Status
- -
-
Description
-
Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain).
-
- -
-
+
+ GET Block Height Blocks + +
+
Description
+
Returns the hash of the block currently at :height.
+
+ +
- - - GET Block Tip Height - - - -
-
Description
-
Returns the height of the last block.
-
- -
-
+
+ GET Block Raw Blocks + +
+
Description
+
Returns the raw block representation in binary.
+
+ +
- - - GET Block Tip Hash - - - -
-
Description
-
Returns the hash of the last block.
-
- -
-
+
+ GET Block Status Blocks + +
+
Description
+
Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain).
+
+ +
- - - GET Block Transaction ID - - - -
-
Description
-
Returns the transaction at index :index within the specified block.
-
- -
-
+
+ GET Block Tip Height Blocks + +
+
Description
+
Returns the height of the last block.
+
+ +
- - - GET Block Transaction IDs - - - -
-
Description
-
Returns a list of all txids in the block.
-
- -
-
+
+ GET Block Tip Hash Blocks + +
+
Description
+
Returns the hash of the last block.
+
+ +
- - - GET Block Transactions - - - -
-
Description
-
Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status.
-
- -
-
+
+ GET Block Transaction ID Blocks + +
+
Description
+
Returns the transaction at index :index within the specified block.
+
+ +
- - - GET Blocks - - - -
-
Description
-
Returns the 10 newest blocks starting at the tip or at :start_height if specified.
-
- -
-
+
+ GET Block Transaction IDs Blocks + +
+
Description
+
Returns a list of all txids in the block.
+
+ +
- - - GET Blocks - - - -
-
Description
-
Returns the 10 newest blocks starting at the tip or at :start_height if specified.
-
- -
-
+
+ GET Block Transactions Blocks + +
+
Description
+
Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status.
+
+ +
- -
+
+ GET Blocks Blocks + +
+
Description
+
Returns the 10 newest blocks starting at the tip or at :start_height if specified.
+
+ +
-
-

Fees

- +
+ GET Blocks Blocks + +
+
Description
+
Returns the 10 newest blocks starting at the tip or at :start_height if specified.
+
+ +
- - - GET Mempool Blocks Fees - - - -
-
Description
-
Returns current mempool as projected blocks.
-
- -
-
+
- - - GET Recommended Fees - - - -
-
Description
-
Returns our currently suggested fees for new transactions.
-
- -
-
+
- -
+
+ GET Mempool Blocks Fees Fees + +
+
Description
+
Returns current mempool as projected blocks.
+
+ +
-
-

Mempool

- + - - - GET Mempool - - - -
-
Description
-
Returns current mempool backlog statistics.
-
- -
-
+
- - - GET Mempool Transactions IDs - - - -
-
Description
-
Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.
-
- -
-
+
- - - GET Mempool Recent - - - -
-
Description
-
Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value.
-
- -
-
+
+ GET Mempool Fees + +
+
Description
+
Returns current mempool backlog statistics.
+
+ +
- -
+
+ GET Mempool Transactions IDs Fees + +
+
Description
+
Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.
+
+ +
-
-

Transactions

- +
+ GET Mempool Recent Fees + +
+
Description
+
Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value.
+
+ +
- - - GET Children Pay for Parent - - - -
-
Description
-
Returns the ancestors and the best descendant fees for a transaction.
-
- -
-
+
- - - GET Transaction - - - -
-
Description
-
Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status.
-
- -
-
+
- - - GET Transaction Hex - - - -
-
Description
-
Returns a transaction serialized as hex.
-
- -
-
+
+ GET Children Pay for Parent Transactions + +
+
Description
+
Returns the ancestors and the best descendant fees for a transaction.
+
+ +
- - - GET Transaction Merkleblock Proof - - - -
-
Description
-
Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format.
-
- -
-
+
+ GET Transaction Transactions + +
+
Description
+
Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status.
+
+ +
- - - GET Transaction Merkle Proof - - -
-
Endpoint
- GET {{ baseNetworkUrl }}/api/tx/:txid/merkle-proof +
+ GET Transaction Hex Transactions + -
-
Description
-
Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format.
-
- - - +
+
Description
+
Returns a transaction serialized as hex.
+
+ +
- - - GET Transaction Outspend - - - -
-
Description
-
Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx).
-
- -
-
+
+ GET Transaction Merkleblock Proof Transactions + +
+
Description
+
Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format.
+
+ +
- - - GET Transaction Outspends - - - -
-
Description
-
Returns the spending status of all transaction outputs.
-
- -
-
+
+ GET Transaction Merkle Proof Transactions + +
+
Description
+
Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format.
+
+ +
- - - GET Transaction Raw - - - -
-
Description
-
Returns a transaction as binary data.
-
- -
-
+
+ GET Transaction Outspend Transactions + +
+
Description
+
Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx).
+
+ +
- - - GET Transaction Status - - - -
-
Description
-
Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional).
-
- -
-
+
+ GET Transaction Outspends Transactions + +
+
Description
+
Returns the spending status of all transaction outputs.
+
+ +
- - - GET Transactions - - -
Get Mempool Txids
- -
-
Description
-
Returns :length of latest Bisq transactions, starting from :index.
-
- -
-
+
+ GET Transaction Raw Transactions + +
+
Description
+
Returns a transaction as binary data.
+
+ +
- - - POST Transaction - - -
-
Endpoint
-
POST /api/tx
-
-
-
Description
-
Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success.
-
- -
-
+
+ GET Transaction Status Transactions + +
+
Description
+
Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional).
+
+ +
- +
+ GET Transactions Transactions + +
+
Description
+
Returns :length of latest Bisq transactions, starting from :index.
+
+ +
+ +
+ POST Transaction Transactions +
+
Endpoint
+
POST /api/tx
+
+
+
Description
+
Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success.
+
+ +
+ +
@@ -868,13 +701,5 @@
-
- - -
diff --git a/frontend/src/app/components/docs/api-docs.component.scss b/frontend/src/app/components/docs/api-docs.component.scss index e9d2cf52e..d03608e92 100644 --- a/frontend/src/app/components/docs/api-docs.component.scss +++ b/frontend/src/app/components/docs/api-docs.component.scss @@ -22,6 +22,10 @@ li.nav-item { } } +.no-bottom-space { + margin-bottom: 0; +} + .nav-tabs .nav-link.active { border-bottom: 1px solid #fff; @media (min-width: 676px){ @@ -72,10 +76,131 @@ li.nav-item { padding: 15px; } -#restAPI .api-category { - margin: 30px 0; +#doc-nav-desktop { + width: 300px; } -.api-category h4 { - margin-bottom: 15px; +#doc-nav-desktop.relative { + float: left; + overflow: hidden; +} + +#doc-nav-desktop.fixed { + float: unset; + position: fixed; + top: 20px; + overflow-y: auto; + height: calc(100vh - 50px); + scrollbar-color: #2d3348 #11131f; + scrollbar-width: thin; +} +::-webkit-scrollbar { + width: 3px; +} +::-webkit-scrollbar-track { + background: #11131f; +} +::-webkit-scrollbar-thumb { + background-color: #2d3348; + border-radius: 5px; + border: none; +} + +.doc-content { + width: calc(100% - 330px); + float: right; +} + +.endpoint-container:before { + display: block; + content: " "; + height: 1px; + margin-top: -1px; + visibility: hidden; +} + +.endpoint-container .section-header { + display: block; + background-color: #2d3348; + color: #1bd8f4; + padding: 1rem 1.3rem 1rem 1.3rem; + font-weight: bold; + border-radius: 0.25rem; + margin: 20px 0 20px 0; + font-size: 24px; + position: relative; +} +.endpoint-container .section-header:hover { + text-decoration: none; +} + +.endpoint-container .section-header span { + color: #fff; + background-color: #653b9c; + font-size: 12px; + text-transform: uppercase; + font-weight: 400; + padding: 8px 10px; + letter-spacing: 1px; + border-radius: 0.25rem; + font-family: monospace; + float: right; +} + +#doc-nav-mobile { + position: fixed; + top: 20px; + width: calc(100% - 60px); + z-index: 100; +} + +#doc-nav-mobile > div { + background-color: #2d3348; + z-index: 100; + border-radius: 0 0 0.5rem 0.5rem; + height: 55vh; + overflow-y: auto; +} + +#doc-nav-mobile button { + width: 100%; + background-color: #105fb0; + color: #fff; + border-color: #105fb0; + border-radius: 0.5rem 0.5rem 0 0; +} + +@media (max-width: 992px) { + + .hide-on-mobile { + display: none; + } + + .doc-content { + width: 100%; + } + + .endpoint-container .section-header { + margin: 40px 0 70px 0; + } + + .endpoint-container .section-header span { + float: none; + position: absolute; + top: unset; + left: 0; + bottom: -50px; + } + + .endpoint-container:before { + height: 30px; + margin-top: -12px; + } + +} + +@media (min-width: 992px) { + .hide-on-desktop { + display: none; + } } diff --git a/frontend/src/app/components/docs/api-docs.component.ts b/frontend/src/app/components/docs/api-docs.component.ts index a38ded836..02cca44b2 100644 --- a/frontend/src/app/components/docs/api-docs.component.ts +++ b/frontend/src/app/components/docs/api-docs.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, OnInit, Input, ViewChild, ElementRef } from '@angular/core'; import { Env, StateService } from 'src/app/services/state.service'; import { Observable, merge, of } from 'rxjs'; import { SeoService } from 'src/app/services/seo.service'; @@ -17,12 +17,26 @@ export class ApiDocsComponent implements OnInit { code: any; baseNetworkUrl = ''; @Input() restTabActivated: Boolean; + @ViewChild( "mobileFixedApiNav", { static: false } ) mobileFixedApiNav: ElementRef; + desktopDocsNavPosition = "relative"; + showFloatingDocsNav = false; + mobileMenuOpen = true; constructor( private stateService: StateService, private seoService: SeoService, ) { } + ngAfterViewInit() { + const that = this; + setTimeout( () => { + window.addEventListener('scroll', function() { + that.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative"; + that.showFloatingDocsNav = ( window.pageYOffset > ( that.mobileFixedApiNav.nativeElement.offsetHeight + 188 ) ) ? true : false; + }); + }, 1 ); + } + ngOnInit(): void { this.env = this.stateService.env; this.seoService.setTitle($localize`:@@e351b40b3869a5c7d19c3d4918cb1ac7aaab95c4:API`); @@ -628,24 +642,6 @@ export class ApiDocsComponent implements OnInit { console.log(asset); `, }, - codeSampleMainnet: { - esModule: [], - commonJS: [], - curl: [], - response: '' - }, - codeSampleTestnet: { - esModule: [], - commonJS: [], - curl: [], - response: '' - }, - codeSampleSignet: { - esModule: [], - commonJS: [], - curl: [], - response: '' - }, codeSampleLiquid: { esModule: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], commonJS: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], @@ -679,6 +675,47 @@ export class ApiDocsComponent implements OnInit { response: '' }, }, + assetIcons: { + codeTemplate: { + curl: `/api/v1/assets/icons`, + commonJS: ` + const { %{0}: { assets } } = mempoolJS(); + + const assetsIcons = await assets.getAssetsIcons(); + + document.getElementById("result").textContent = JSON.stringify(assetsIcons, undefined, 2); + `, + esModule: ` + const { %{0}: { assets } } = mempoolJS(); + + const assetsIcons = await assets.getAssetsIcons(); + console.log(assetsIcons); + `, + }, + codeSampleLiquid: { + esModule: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], + commonJS: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], + curl: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], + response: `[ + "6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d", + "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2" + ... +]`, + }, + }, + assetIcon: { + noWrap: true, + codeTemplate: { + curl: `/api/v1/asset/%{1}/icon`, + commonJS: ``, + }, + codeSampleLiquid: { + esModule: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], + commonJS: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], + curl: [`6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`], + response: `PNG`, + }, + }, assetTransactions: { codeTemplate: { curl: `/api/asset/%{1}/txs`, diff --git a/frontend/src/app/components/docs/code-template.component.ts b/frontend/src/app/components/docs/code-template.component.ts index e84297f80..0c46c7a9d 100644 --- a/frontend/src/app/components/docs/code-template.component.ts +++ b/frontend/src/app/components/docs/code-template.component.ts @@ -164,6 +164,10 @@ init();`; codeText = this.replaceJSPlaceholder(codeText, code.codeSampleBisq.esModule); } + if (code.noWrap) { + return codeText; + } + let importText = ``; if (this.env.BASE_MODULE === 'bisq') { importText = ``; diff --git a/frontend/src/app/components/docs/docs.component.html b/frontend/src/app/components/docs/docs.component.html index f67ed8e32..8dc4a9e72 100644 --- a/frontend/src/app/components/docs/docs.component.html +++ b/frontend/src/app/components/docs/docs.component.html @@ -27,5 +27,13 @@
+
+ + +
diff --git a/frontend/src/app/components/docs/docs.component.scss b/frontend/src/app/components/docs/docs.component.scss index 404782585..6398c5602 100644 --- a/frontend/src/app/components/docs/docs.component.scss +++ b/frontend/src/app/components/docs/docs.component.scss @@ -1,4 +1,9 @@ #main-tab-content { text-align: left; padding-top: 10px; + scroll-behavior: smooth; +} + +#footer { + clear: both; } diff --git a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts index 622b8a296..4f982a269 100644 --- a/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts +++ b/frontend/src/app/components/incoming-transactions-graph/incoming-transactions-graph.component.ts @@ -1,8 +1,8 @@ import { Component, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnInit } from '@angular/core'; -import { formatDate } from '@angular/common'; import { EChartsOption } from 'echarts'; import { OnChanges } from '@angular/core'; import { StorageService } from 'src/app/services/storage.service'; +import { formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils'; @Component({ selector: 'app-incoming-transactions-graph', @@ -25,6 +25,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { @Input() top: number | string = '20'; @Input() left: number | string = '0'; @Input() template: ('widget' | 'advanced') = 'widget'; + @Input() windowPreferenceOverride: string; isLoading = true; mempoolStatsChartOption: EChartsOption = {}; @@ -46,7 +47,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { if (!this.data) { return; } - this.windowPreference = this.storageService.getValue('graphWindowPreference'); + this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference'); this.mountChart(); } @@ -73,10 +74,12 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { maxSpan: 100, minSpan: 10, }, { + showDetail: false, show: (this.template === 'advanced') ? true : false, type: 'slider', brushSelect: false, realtime: true, + bottom: 0, selectedDataBackground: { lineStyle: { color: '#fff', @@ -85,7 +88,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { areaStyle: { opacity: 0, } - } + }, }], tooltip: { trigger: 'axis', @@ -102,29 +105,39 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { + const axisValueLabel: string = formatterXAxis(this.locale, this.windowPreference, params[0].axisValue); const colorSpan = (color: string) => ``; - let itemFormatted = '
' + params[0].axisValue + '
'; + let itemFormatted = '
' + axisValueLabel + '
'; params.map((item: any, index: number) => { if (index < 26) { itemFormatted += `
${colorSpan(item.color)}
-
${item.value} vB/s
+
${item.value[1]} vB/s
`; } }); return `
${itemFormatted}
`; } }, - xAxis: { - type: 'category', - axisLabel: { - align: 'center', - fontSize: 11, - lineHeight: 12 - }, - data: this.data.labels.map((value: any) => `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}`), - }, + xAxis: [ + { + name: formatterXAxisLabel(this.locale, this.windowPreference), + nameLocation: 'middle', + nameTextStyle: { + padding: [20, 0, 0, 0], + }, + type: 'time', + axisLabel: { + margin: 20, + align: 'center', + fontSize: 11, + lineHeight: 12, + hideOverlap: true, + padding: [0, 5], + }, + } + ], yAxis: { type: 'value', axisLabel: { diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 680563b4c..ca3a7270f 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -3,7 +3,8 @@
-   +  
~{{ projectedBlock.medianFee | number:feeRounding }} sat/vB diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss index 92c40c73b..68ed1e26c 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.scss @@ -117,6 +117,10 @@ z-index: 10; } +.blockLink.disabled { + pointer-events: none; +} + .blockLink:hover { text-decoration: none; } diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts index 3fd8912fd..35dacbe26 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -1,13 +1,12 @@ import { Component, OnInit, Input, Inject, LOCALE_ID, ChangeDetectionStrategy, OnChanges } from '@angular/core'; -import { formatDate } from '@angular/common'; import { VbytesPipe } from 'src/app/shared/pipes/bytes-pipe/vbytes.pipe'; import { formatNumber } from "@angular/common"; - import { OptimizedMempoolStats } from 'src/app/interfaces/node-api.interface'; import { StateService } from 'src/app/services/state.service'; import { StorageService } from 'src/app/services/storage.service'; import { EChartsOption } from 'echarts'; import { feeLevels, chartColors } from 'src/app/app.constants'; +import { formatterXAxis, formatterXAxisLabel } from 'src/app/shared/graphs.utils'; @Component({ selector: 'app-mempool-graph', @@ -32,6 +31,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { @Input() left: number | string = 75; @Input() template: ('widget' | 'advanced') = 'widget'; @Input() showZoom = true; + @Input() windowPreferenceOverride: string; isLoading = true; mempoolVsizeFeesData: any; @@ -62,7 +62,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { if (!this.data) { return; } - this.windowPreference = this.storageService.getValue('graphWindowPreference'); + this.windowPreference = this.windowPreferenceOverride ? this.windowPreferenceOverride : this.storageService.getValue('graphWindowPreference'); this.mempoolVsizeFeesData = this.handleNewMempoolData(this.data.concat([])); this.mountFeeChart(); } @@ -97,13 +97,13 @@ export class MempoolGraphComponent implements OnInit, OnChanges { } generateArray(mempoolStats: OptimizedMempoolStats[]) { - const finalArray: number[][] = []; - let feesArray: number[] = []; + const finalArray: number[][][] = []; + let feesArray: number[][] = []; let limitFeesTemplate = this.template === 'advanced' ? 26 : 20; for (let index = limitFeesTemplate; index > -1; index--) { feesArray = []; mempoolStats.forEach((stats) => { - feesArray.push(stats.vsizes[index] ? stats.vsizes[index] : 0); + feesArray.push([stats.added * 1000, stats.vsizes[index] ? stats.vsizes[index] : 0]); }); finalArray.push(feesArray); } @@ -113,7 +113,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { mountFeeChart() { this.orderLevels(); - const { labels, series } = this.mempoolVsizeFeesData; + const { series } = this.mempoolVsizeFeesData; const seriesGraph = []; const newColors = []; @@ -186,14 +186,15 @@ export class MempoolGraphComponent implements OnInit, OnChanges { type: 'line', }, formatter: (params: any) => { + const axisValueLabel: string = formatterXAxis(this.locale, this.windowPreference, params[0].axisValue); const { totalValue, totalValueArray } = this.getTotalValues(params); const itemFormatted = []; let totalParcial = 0; let progressPercentageText = ''; const items = this.inverted ? [...params].reverse() : params; items.map((item: any, index: number) => { - totalParcial += item.value; - const progressPercentage = (item.value / totalValue) * 100; + totalParcial += item.value[1]; + const progressPercentage = (item.value[1] / totalValue) * 100; const progressPercentageSum = (totalValueArray[index] / totalValue) * 100; let activeItemClass = ''; let hoverActive = 0; @@ -233,7 +234,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { - ${this.vbytesPipe.transform(item.value, 2, 'vB', 'MvB', false)} + ${this.vbytesPipe.transform(item.value[1], 2, 'vB', 'MvB', false)} @@ -257,7 +258,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const titleSum = $localize`Sum`; return `
- ${params[0].axisValue} + ${axisValueLabel} ${this.vbytesPipe.transform(totalValue, 2, 'vB', 'MvB', false)} @@ -288,6 +289,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { maxSpan: 100, minSpan: 10, }, { + showDetail: false, show: (this.template === 'advanced' && this.showZoom) ? true : false, type: 'slider', brushSelect: false, @@ -312,15 +314,22 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }, xAxis: [ { - type: 'category', + name: formatterXAxisLabel(this.locale, this.windowPreference), + nameLocation: 'middle', + nameTextStyle: { + padding: [20, 0, 0, 0], + }, + type: 'time', boundaryGap: false, axisLine: { onZero: true }, axisLabel: { + margin: 20, align: 'center', fontSize: 11, lineHeight: 12, + hideOverlap: true, + padding: [0, 5], }, - data: labels.map((value: any) => `${formatDate(value, 'M/d', this.locale)}\n${formatDate(value, 'H:mm', this.locale)}`), } ], yAxis: { @@ -346,7 +355,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const totalValueArray = []; const valuesInverted = this.inverted ? values : [...values].reverse(); for (const item of valuesInverted) { - totalValueTemp += item.value; + totalValueTemp += item.value[1]; totalValueArray.push(totalValueTemp); } return { diff --git a/frontend/src/app/components/start/start.component.html b/frontend/src/app/components/start/start.component.html index cf8eb80ad..9d7f39ba2 100644 --- a/frontend/src/app/components/start/start.component.html +++ b/frontend/src/app/components/start/start.component.html @@ -8,8 +8,11 @@
{{ eventName }} in {{ countdown | number }} block{{ countdown === 1 ? '' : 's' }}!
-
- +
+
diff --git a/frontend/src/app/components/start/start.component.ts b/frontend/src/app/components/start/start.component.ts index ec2b41472..9fe4e44e0 100644 --- a/frontend/src/app/components/start/start.component.ts +++ b/frontend/src/app/components/start/start.component.ts @@ -1,8 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core'; import { WebsocketService } from 'src/app/services/websocket.service'; import { StateService } from 'src/app/services/state.service'; import { specialBlocks } from 'src/app/app.constants'; -import { takeLast } from 'rxjs/operators'; @Component({ selector: 'app-start', @@ -16,6 +15,9 @@ export class StartComponent implements OnInit { countdown = 0; specialEvent = false; eventName = ''; + mouseDragStartX: number; + blockchainScrollLeftInit: number; + @ViewChild('blockchainContainer') blockchainContainer: ElementRef; constructor( private websocketService: WebsocketService, @@ -50,4 +52,27 @@ export class StartComponent implements OnInit { }); } + onMouseDown(event: MouseEvent) { + this.mouseDragStartX = event.clientX; + this.blockchainScrollLeftInit = this.blockchainContainer.nativeElement.scrollLeft; + } + onDragStart(event: MouseEvent) { // Ignore Firefox annoying default drag behavior + event.preventDefault(); + } + + // We're catching the whole page event here because we still want to scroll blocks + // even if the mouse leave the blockchain blocks container. Same idea for mouseup below. + @HostListener('document:mousemove', ['$event']) + onMouseMove(event: MouseEvent): void { + if (this.mouseDragStartX != null) { + this.stateService.setBlockScrollingInProgress(true); + this.blockchainContainer.nativeElement.scrollLeft = + this.blockchainScrollLeftInit + this.mouseDragStartX - event.clientX + } + } + @HostListener('document:mouseup', []) + onMouseUp() { + this.mouseDragStartX = null; + this.stateService.setBlockScrollingInProgress(false); + } } diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts index fb386304d..84513fd3f 100644 --- a/frontend/src/app/components/statistics/statistics.component.ts +++ b/frontend/src/app/components/statistics/statistics.component.ts @@ -134,7 +134,7 @@ export class StatisticsComponent implements OnInit { this.mempoolTransactionsWeightPerSecondData = { labels: labels, - series: [mempoolStats.map((stats) => stats.vbytes_per_second)], + series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])], }; } diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 1085f6335..41aad22cd 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -20,8 +20,6 @@ - -
- +
diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss index d7d9fb5df..4628c35f9 100644 --- a/frontend/src/app/components/transaction/transaction.component.scss +++ b/frontend/src/app/components/transaction/transaction.component.scss @@ -3,25 +3,11 @@ } .container-buttons { - text-align: right; - align-self: start; - width: auto; - margin-right: 15px; - right: 0; - position: absolute; - @media (min-width: 650px) { - right: auto; - margin-right: auto; - position: relative; - } - @media (min-width: 768px) { - align-self: center; - float: right; - } + align-self: center; } .title-block { - flex-direction: column; + flex-wrap: wrap; @media (min-width: 650px) { flex-direction: row; } @@ -32,6 +18,7 @@ } .tx-link { display: flex; + flex-grow: 1; margin-bottom: 0px; margin-top: 8px; @media (min-width: 650px) { @@ -45,6 +32,9 @@ top: 1px; position: relative; } + @media (max-width: 768px) { + order: 3; + } } .td-width { @@ -127,7 +117,6 @@ } } - .title { h2 { line-height: 1; @@ -137,7 +126,14 @@ } .btn-outline-info { - margin-top: -10px; + margin-top: 5px; + @media (min-width: 768px){ + margin-top: 0px; + } +} + +.details-button { + margin-top: -5px; @media (min-width: 768px){ display: inline-block; margin-top: 0px; diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 530c365a0..36c018761 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -54,6 +54,7 @@ [limitFee]="150" [limitFilterFee]="1" [data]="mempoolStats.value?.mempool" + [windowPreferenceOverride]="'2h'" >
@@ -73,6 +74,7 @@
diff --git a/frontend/src/app/dashboard/dashboard.component.ts b/frontend/src/app/dashboard/dashboard.component.ts index ea843ec29..7cc6a2aec 100644 --- a/frontend/src/app/dashboard/dashboard.component.ts +++ b/frontend/src/app/dashboard/dashboard.component.ts @@ -254,7 +254,6 @@ export class DashboardComponent implements OnInit { ); }), map((mempoolStats) => { - const data = this.handleNewMempoolData(mempoolStats.concat([])); return { mempool: mempoolStats, weightPerSecond: this.handleNewMempoolData(mempoolStats.concat([])), @@ -286,7 +285,7 @@ export class DashboardComponent implements OnInit { return { labels: labels, - series: [mempoolStats.map((stats) => stats.vbytes_per_second)], + series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])], }; } diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 550f712d9..04091b0ad 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -1,6 +1,6 @@ export interface OptimizedMempoolStats { id: number; - added: string; + added: number; unconfirmed_transactions: number; tx_per_second: number; vbytes_per_second: number; @@ -42,7 +42,7 @@ export interface AddressInformation { scriptPubKey: string; // (string) The hex-encoded scriptPubKey generated by the address isscript: boolean; // (boolean) If the key is a script iswitness: boolean; // (boolean) If the address is a witness - witness_version?: boolean; // (numeric, optional) The version number of the witness program + witness_version?: number; // (numeric, optional) The version number of the witness program witness_program: string; // (string, optional) The hex value of the witness program confidential_key?: string; // (string) Elements only unconfidential?: string; // (string) Elements only diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 20b28f2e5..604bb6a87 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -89,6 +89,8 @@ export class StateService { markBlock$ = new ReplaySubject(); keyNavigation$ = new Subject(); + blockScrolling$: Subject = new Subject(); + constructor( @Inject(PLATFORM_ID) private platformId: any, private router: Router, @@ -176,4 +178,8 @@ export class StateService { if (!prop) { return false; } return document[prop]; } + + setBlockScrollingInProgress(value: boolean) { + this.blockScrolling$.next(value); + } } diff --git a/frontend/src/app/services/storage.service.ts b/frontend/src/app/services/storage.service.ts index c7595b404..7494784f6 100644 --- a/frontend/src/app/services/storage.service.ts +++ b/frontend/src/app/services/storage.service.ts @@ -1,9 +1,25 @@ import { Injectable } from '@angular/core'; +import { Router, ActivatedRoute } from '@angular/router'; @Injectable({ providedIn: 'root' }) export class StorageService { + constructor(private router: Router, private route: ActivatedRoute) { + let graphWindowPreference: string = this.getValue('graphWindowPreference'); + if (graphWindowPreference === null) { // First visit to mempool.space + if (this.router.url.includes("graphs")) { + this.setValue('graphWindowPreference', this.route.snapshot.fragment ? this.route.snapshot.fragment : "2h"); + } else { + this.setValue('graphWindowPreference', "2h"); + } + } else if (this.router.url.includes("graphs")) { // Visit a different graphs#fragment from last visit + if (this.route.snapshot.fragment !== null && graphWindowPreference !== this.route.snapshot.fragment) { + this.setValue('graphWindowPreference', this.route.snapshot.fragment); + } + } + } + getValue(key: string): string { try { return localStorage.getItem(key); diff --git a/frontend/src/app/shared/graphs.utils.ts b/frontend/src/app/shared/graphs.utils.ts new file mode 100644 index 000000000..e0ffe841e --- /dev/null +++ b/frontend/src/app/shared/graphs.utils.ts @@ -0,0 +1,49 @@ +export const formatterXAxis = ( + locale: string, + windowPreference: string, + value: string +) => { + + if(value.length === 0){ + return null; + } + + const date = new Date(value); + switch (windowPreference) { + case '2h': + return date.toLocaleTimeString(locale, { hour: 'numeric', minute: 'numeric' }); + case '24h': + return date.toLocaleTimeString(locale, { weekday: 'short', hour: 'numeric', minute: 'numeric' }); + case '1w': + case '1m': + case '3m': + case '6m': + case '1y': + return date.toLocaleTimeString(locale, { month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric' }); + case '2y': + case '3y': + return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); + } +}; + +export const formatterXAxisLabel = ( + locale: string, + windowPreference: string, +) => { + const date = new Date(); + switch (windowPreference) { + case '2h': + case '24h': + return date.toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); + case '1w': + return date.toLocaleDateString(locale, { year: 'numeric', month: 'long' }); + case '1m': + case '3m': + case '6m': + return date.toLocaleDateString(locale, { year: 'numeric' }); + case '1y': + case '2y': + case '3y': + return null; + } +}; diff --git a/frontend/src/locale/messages.xlf b/frontend/src/locale/messages.xlf index cc3648909..f142c56ff 100644 --- a/frontend/src/locale/messages.xlf +++ b/frontend/src/locale/messages.xlf @@ -253,7 +253,7 @@ Registered assets src/app/assets/assets.component.html - 3,7 + 3,8 Registered assets page header @@ -325,7 +325,7 @@ Error loading assets data. src/app/assets/assets.component.html - 63,68 + 63,71 Asset data load error @@ -341,7 +341,7 @@ src/app/components/master-page/master-page.component.html - 58,60 + 58,61 @@ -364,7 +364,7 @@ src/app/components/address/address.component.html - 28,29 + 31,32 address.total-received @@ -380,7 +380,7 @@ src/app/components/address/address.component.html - 32,33 + 35,36 address.total-sent @@ -392,7 +392,7 @@ src/app/components/address/address.component.html - 37,38 + 40,41 address.balance @@ -412,11 +412,11 @@ src/app/components/blockchain-blocks/blockchain-blocks.component.html - 18,19 + 19,20 src/app/components/mempool-blocks/mempool-blocks.component.html - 17,18 + 18,19 shared.transaction-count.singular @@ -436,11 +436,11 @@ src/app/components/blockchain-blocks/blockchain-blocks.component.html - 19,20 + 20,21 src/app/components/mempool-blocks/mempool-blocks.component.html - 18,19 + 19,20 shared.transaction-count.plural @@ -495,7 +495,7 @@ src/app/components/transaction/transaction.component.html - 51,53 + 49,52 Transaction Timestamp transaction.timestamp @@ -532,7 +532,7 @@ Height src/app/bisq/bisq-blocks/bisq-blocks.component.html - 12,13 + 12,14 src/app/bisq/bisq-transactions/bisq-transactions.component.html @@ -544,7 +544,7 @@ src/app/dashboard/dashboard.component.html - 89,90 + 91,93 Bisq block height header @@ -552,11 +552,11 @@ Confirmed src/app/bisq/bisq-blocks/bisq-blocks.component.html - 13,14 + 13,15 src/app/bisq/bisq-transactions/bisq-transactions.component.html - 21,23 + 21,24 Bisq block confirmed time header @@ -576,7 +576,7 @@ src/app/components/latest-blocks/latest-blocks.component.html - 12,15 + 12,16 src/app/components/master-page/master-page.component.html @@ -608,11 +608,11 @@ src/app/components/master-page/master-page.component.html - 40,42 + 40,43 src/app/components/master-page/master-page.component.html - 48,50 + 48,51 @@ -637,17 +637,13 @@ src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.html 66,67 - - src/app/components/api-docs/api-docs.component.html - 36,38 - Bisq All Markets Bitcoin Markets src/app/bisq/bisq-dashboard/bisq-dashboard.component.html - 21,23 + 21,24 src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.html @@ -717,7 +713,7 @@ Latest Trades src/app/bisq/bisq-dashboard/bisq-dashboard.component.html - 52,55 + 52,56 src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.html @@ -753,11 +749,11 @@ src/app/bisq/bisq-main-dashboard/bisq-main-dashboard.component.html - 101,107 + 101,108 src/app/dashboard/dashboard.component.html - 108,112 + 110,115 dashboard.view-all @@ -769,15 +765,15 @@ src/app/components/about/about.component.html - 223,227 + 239,243 - src/app/components/api-docs/api-docs.component.html - 893,895 + src/app/components/docs/docs.component.html + 33 src/app/dashboard/dashboard.component.html - 150,152 + 152,154 Terms of Service shared.terms-of-service @@ -929,7 +925,7 @@ src/app/dashboard/dashboard.component.html - 119,120 + 121,122 @@ -973,11 +969,11 @@ src/app/components/transaction/transaction.component.html - 153,155 + 151,153 src/app/components/transactions-list/transactions-list.component.html - 198,199 + 211,213 @@ -992,7 +988,7 @@ src/app/components/transaction/transaction.component.html - 232,234 + 230,232 transaction.version @@ -1013,7 +1009,8 @@ shared.transaction - confirmation + confirmation src/app/bisq/bisq-transaction/bisq-transaction.component.html 20,21 @@ -1024,17 +1021,24 @@ src/app/components/transaction/transaction.component.html - 29,30 + 27,28 src/app/components/transactions-list/transactions-list.component.html - 225,226 + 238,239 Transaction singular confirmation count shared.confirmation-count.singular - confirmations + confirmations src/app/bisq/bisq-transaction/bisq-transaction.component.html 21,22 @@ -1045,11 +1049,11 @@ src/app/components/transaction/transaction.component.html - 30,31 + 28,29 src/app/components/transactions-list/transactions-list.component.html - 226,227 + 239,240 Transaction plural confirmation count shared.confirmation-count.plural @@ -1062,7 +1066,7 @@ src/app/components/transaction/transaction.component.html - 60,62 + 58,60 Transaction included in block transaction.included-in-block @@ -1075,11 +1079,11 @@ src/app/components/transaction/transaction.component.html - 72,75 + 70,73 src/app/components/transaction/transaction.component.html - 130,133 + 128,131 Transaction features transaction.features @@ -1105,11 +1109,11 @@ src/app/components/transaction/transaction.component.html - 206,210 + 204,209 src/app/components/transaction/transaction.component.html - 318,323 + 316,322 transaction.details @@ -1125,11 +1129,11 @@ src/app/components/transaction/transaction.component.html - 196,199 + 194,197 src/app/components/transaction/transaction.component.html - 289,295 + 287,293 Transaction inputs and outputs transaction.inputs-and-outputs @@ -1160,11 +1164,11 @@ src/app/components/transaction/transaction.component.html - 154,155 + 152,153 src/app/dashboard/dashboard.component.html - 118,119 + 120,121 @@ -1301,7 +1305,7 @@ The Mempool Open Source Project src/app/components/about/about.component.html - 12 + 12,13 about.about-the-project @@ -1316,7 +1320,7 @@ Enterprise Sponsors 🚀 src/app/components/about/about.component.html - 35,37 + 35,38 about.sponsors.enterprise.withRocket @@ -1324,7 +1328,7 @@ Community Sponsors ❤️ src/app/components/about/about.component.html - 61,64 + 65,68 about.sponsors.withHeart @@ -1332,7 +1336,7 @@ Become a sponsor ❤️ src/app/components/about/about.component.html - 73,74 + 77,78 about.become-a-sponsor @@ -1340,7 +1344,7 @@ Navigate to https://mempool.space/sponsor to sponsor src/app/components/about/about.component.html - 74 + 78 src/app/components/sponsor/sponsor.component.html @@ -1352,7 +1356,7 @@ Community Integrations src/app/components/about/about.component.html - 78,81 + 82,85 about.integrations @@ -1360,7 +1364,7 @@ Community Alliances src/app/components/about/about.component.html - 149,151 + 153,155 about.alliances @@ -1368,15 +1372,23 @@ Project Contributors src/app/components/about/about.component.html - 164,166 + 169,171 about.contributors + + Project Members + + src/app/components/about/about.component.html + 181,183 + + about.project_members + Project Maintainers src/app/components/about/about.component.html - 178,180 + 194,196 about.maintainers @@ -1384,7 +1396,7 @@ About src/app/components/about/about.component.ts - 36 + 37 src/app/components/bisq-master-page/bisq-master-page.component.html @@ -1432,18 +1444,19 @@ address.unconfidential - of transaction + of transaction src/app/components/address/address.component.html - 57,58 + 60,61 X of X Address Transaction - of transactions + of transactions src/app/components/address/address.component.html - 58,59 + 61,62 X of X Address Transactions (Plural) @@ -1451,15 +1464,16 @@ Error loading address data. src/app/components/address/address.component.html - 129,131 + 132,134 address.error.loading-address-data - The number of transactions on this address exceeds the Electrum server limit Consider viewing this address on the official Mempool website instead: + The number of transactions on this address exceeds the Electrum server limit Consider viewing this address on the official Mempool website instead: src/app/components/address/address.component.html - 134,137 + 137,140 Electrum server limit exceeded error @@ -1467,7 +1481,7 @@ Confidential src/app/components/address/address.component.html - 153,155 + 156,158 src/app/components/amount/amount.component.html @@ -1479,11 +1493,11 @@ src/app/components/transactions-list/transactions-list.component.html - 234,236 + 247,249 src/app/dashboard/dashboard.component.html - 126,127 + 128,129 shared.confidential @@ -1494,873 +1508,6 @@ 78 - - API Service - - src/app/components/api-docs/api-docs.component.html - 4,7 - - api-docs.title - - - General - - src/app/components/api-docs/api-docs.component.html - 10,12 - - API Docs tab for General - api-docs.tab.general - - - Endpoint - - src/app/components/api-docs/api-docs.component.html - 20,21 - - - src/app/components/api-docs/api-docs.component.html - 46,47 - - - src/app/components/api-docs/api-docs.component.html - 63,64 - - - src/app/components/api-docs/api-docs.component.html - 80,81 - - - src/app/components/api-docs/api-docs.component.html - 97,98 - - - src/app/components/api-docs/api-docs.component.html - 114,115 - - - src/app/components/api-docs/api-docs.component.html - 131,132 - - - src/app/components/api-docs/api-docs.component.html - 148,149 - - - src/app/components/api-docs/api-docs.component.html - 165,166 - - - src/app/components/api-docs/api-docs.component.html - 191,192 - - - src/app/components/api-docs/api-docs.component.html - 216,217 - - - src/app/components/api-docs/api-docs.component.html - 233,234 - - - src/app/components/api-docs/api-docs.component.html - 250,251 - - - src/app/components/api-docs/api-docs.component.html - 267,268 - - - src/app/components/api-docs/api-docs.component.html - 284,285 - - - src/app/components/api-docs/api-docs.component.html - 310,311 - - - src/app/components/api-docs/api-docs.component.html - 343,344 - - - src/app/components/api-docs/api-docs.component.html - 369,370 - - - src/app/components/api-docs/api-docs.component.html - 386,387 - - - src/app/components/api-docs/api-docs.component.html - 403,404 - - - src/app/components/api-docs/api-docs.component.html - 437,438 - - - src/app/components/api-docs/api-docs.component.html - 454,455 - - - src/app/components/api-docs/api-docs.component.html - 471,472 - - - src/app/components/api-docs/api-docs.component.html - 488,489 - - - src/app/components/api-docs/api-docs.component.html - 505,506 - - - src/app/components/api-docs/api-docs.component.html - 522,523 - - - src/app/components/api-docs/api-docs.component.html - 539,540 - - - src/app/components/api-docs/api-docs.component.html - 556,557 - - - src/app/components/api-docs/api-docs.component.html - 581,582 - - - src/app/components/api-docs/api-docs.component.html - 598,599 - - - src/app/components/api-docs/api-docs.component.html - 624,625 - - - src/app/components/api-docs/api-docs.component.html - 641,642 - - - src/app/components/api-docs/api-docs.component.html - 658,659 - - - src/app/components/api-docs/api-docs.component.html - 684,685 - - - src/app/components/api-docs/api-docs.component.html - 717,718 - - - src/app/components/api-docs/api-docs.component.html - 734,735 - - - src/app/components/api-docs/api-docs.component.html - 751,752 - - - src/app/components/api-docs/api-docs.component.html - 768,769 - - - src/app/components/api-docs/api-docs.component.html - 785,786 - - - src/app/components/api-docs/api-docs.component.html - 802,803 - - - src/app/components/api-docs/api-docs.component.html - 819,820 - - - src/app/components/api-docs/api-docs.component.html - 837,838 - - - src/app/components/api-docs/api-docs.component.html - 854,857 - - - src/app/components/api-docs/api-docs.component.html - 874,876 - - Api docs endpoint - - - Description - - src/app/components/api-docs/api-docs.component.html - 24,25 - - - src/app/components/api-docs/api-docs.component.html - 50,51 - - - src/app/components/api-docs/api-docs.component.html - 67,68 - - - src/app/components/api-docs/api-docs.component.html - 84,85 - - - src/app/components/api-docs/api-docs.component.html - 101,102 - - - src/app/components/api-docs/api-docs.component.html - 118,119 - - - src/app/components/api-docs/api-docs.component.html - 135,136 - - - src/app/components/api-docs/api-docs.component.html - 152,153 - - - src/app/components/api-docs/api-docs.component.html - 169,170 - - - src/app/components/api-docs/api-docs.component.html - 195,196 - - - src/app/components/api-docs/api-docs.component.html - 220,221 - - - src/app/components/api-docs/api-docs.component.html - 237,238 - - - src/app/components/api-docs/api-docs.component.html - 254,255 - - - src/app/components/api-docs/api-docs.component.html - 271,272 - - - src/app/components/api-docs/api-docs.component.html - 288,289 - - - src/app/components/api-docs/api-docs.component.html - 314,315 - - - src/app/components/api-docs/api-docs.component.html - 330,331 - - - src/app/components/api-docs/api-docs.component.html - 347,348 - - - src/app/components/api-docs/api-docs.component.html - 373,374 - - - src/app/components/api-docs/api-docs.component.html - 390,391 - - - src/app/components/api-docs/api-docs.component.html - 407,408 - - - src/app/components/api-docs/api-docs.component.html - 423,424 - - - src/app/components/api-docs/api-docs.component.html - 441,442 - - - src/app/components/api-docs/api-docs.component.html - 458,459 - - - src/app/components/api-docs/api-docs.component.html - 475,476 - - - src/app/components/api-docs/api-docs.component.html - 492,493 - - - src/app/components/api-docs/api-docs.component.html - 509,510 - - - src/app/components/api-docs/api-docs.component.html - 526,527 - - - src/app/components/api-docs/api-docs.component.html - 543,544 - - - src/app/components/api-docs/api-docs.component.html - 560,561 - - - src/app/components/api-docs/api-docs.component.html - 585,586 - - - src/app/components/api-docs/api-docs.component.html - 602,603 - - - src/app/components/api-docs/api-docs.component.html - 628,629 - - - src/app/components/api-docs/api-docs.component.html - 645,646 - - - src/app/components/api-docs/api-docs.component.html - 662,663 - - - src/app/components/api-docs/api-docs.component.html - 688,689 - - - src/app/components/api-docs/api-docs.component.html - 704,705 - - - src/app/components/api-docs/api-docs.component.html - 721,722 - - - src/app/components/api-docs/api-docs.component.html - 738,739 - - - src/app/components/api-docs/api-docs.component.html - 755,756 - - - src/app/components/api-docs/api-docs.component.html - 772,773 - - - src/app/components/api-docs/api-docs.component.html - 789,790 - - - src/app/components/api-docs/api-docs.component.html - 806,807 - - - src/app/components/api-docs/api-docs.component.html - 823,824 - - - src/app/components/api-docs/api-docs.component.html - 841,842 - - - src/app/components/api-docs/api-docs.component.html - 858,859 - - - src/app/components/api-docs/api-docs.component.html - 878,879 - - - - Returns details about difficulty adjustment. - - src/app/components/api-docs/api-docs.component.html - 25,27 - - - - Provides list of available currencies for a given base currency. - - src/app/components/api-docs/api-docs.component.html - 51,53 - - - - Provides list of open offer prices for a single market. - - src/app/components/api-docs/api-docs.component.html - 68,70 - - - - Provides hi/low/open/close data for a given market. This can be used to generate a candlestick chart. - - src/app/components/api-docs/api-docs.component.html - 85,87 - - - - Provides list of available markets. - - src/app/components/api-docs/api-docs.component.html - 102,104 - - - - Provides list of open offer details for a single market. - - src/app/components/api-docs/api-docs.component.html - 119,121 - - - - Provides 24 hour price ticker for single market or all markets - - src/app/components/api-docs/api-docs.component.html - 136,138 - - - - Provides list of completed trades for a single market. - - src/app/components/api-docs/api-docs.component.html - 153,155 - - - - Provides periodic volume data in terms of base currency for one or all markets. - - src/app/components/api-docs/api-docs.component.html - 170,172 - - - - General - - src/app/components/api-docs/api-docs.component.html - 181,183 - - API Docs tab for BSQ - api-docs.tab.bsq - - - Returns statistics about all Bisq transactions. - - src/app/components/api-docs/api-docs.component.html - 196,198 - - - - Addresses - - src/app/components/api-docs/api-docs.component.html - 207,209 - - API Docs tab for Addresses - api-docs.tab.addresses - - - Returns details about an address. Available fields: address, chain_stats, and mempool_stats. chain,mempool_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum. - - src/app/components/api-docs/api-docs.component.html - 221,222 - - - - Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid (see below). - - src/app/components/api-docs/api-docs.component.html - 238,239 - - - - Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query. - - src/app/components/api-docs/api-docs.component.html - 255,257 - - - - Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging). - - src/app/components/api-docs/api-docs.component.html - 272,274 - - - - Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof. - - src/app/components/api-docs/api-docs.component.html - 289,290 - - - - Assets - - src/app/components/api-docs/api-docs.component.html - 300,302 - - API Docs tab for Assets - api-docs.tab.assets - - - Returns information about a Liquid asset. - - src/app/components/api-docs/api-docs.component.html - 315,317 - - - - Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset. - - src/app/components/api-docs/api-docs.component.html - 331,333 - - - - Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units. - - src/app/components/api-docs/api-docs.component.html - 348,350 - - - - Blocks - - src/app/components/api-docs/api-docs.component.html - 359,361 - - - src/app/components/latest-blocks/latest-blocks.component.ts - 39 - - API Docs tab for Blocks - api-docs.tab.blocks - - - Returns details about a block. Available fields: id, height, version, timestamp, bits, nonce, merkle_root, tx_count, size, weight,proof, and previousblockhash. - - src/app/components/api-docs/api-docs.component.html - 374,375 - - - - Returns the hex-encoded block header. - - src/app/components/api-docs/api-docs.component.html - 391,393 - - - - Returns the hash of the block currently at :height. - - src/app/components/api-docs/api-docs.component.html - 408,409 - - - - Returns the raw block representation in binary. - - src/app/components/api-docs/api-docs.component.html - 424,426 - - - - Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain). - - src/app/components/api-docs/api-docs.component.html - 442,443 - - - - Returns the height of the last block. - - src/app/components/api-docs/api-docs.component.html - 459,461 - - - - Returns the hash of the last block. - - src/app/components/api-docs/api-docs.component.html - 476,478 - - - - Returns the transaction at index :index within the specified block. - - src/app/components/api-docs/api-docs.component.html - 493,494 - - - - Returns a list of all txids in the block. - - src/app/components/api-docs/api-docs.component.html - 510,512 - - - - Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status. - - src/app/components/api-docs/api-docs.component.html - 527,528 - - - - Returns the 10 newest blocks starting at the tip or at :start_height if specified. - - src/app/components/api-docs/api-docs.component.html - 544,545 - - - src/app/components/api-docs/api-docs.component.html - 561,562 - - - - Fees - - src/app/components/api-docs/api-docs.component.html - 571,573 - - API Docs tab for Fees - api-docs.tab.fees - - - Returns current mempool as projected blocks. - - src/app/components/api-docs/api-docs.component.html - 586,588 - - API Docs for /api/v1/fees/mempool-blocks - api-docs.fees.mempool-blocks - - - Returns our currently suggested fees for new transactions. - - src/app/components/api-docs/api-docs.component.html - 603,605 - - API Docs for /api/v1/fees/recommended - api-docs.fees.recommended - - - Mempool - - src/app/components/api-docs/api-docs.component.html - 614,616 - - API Docs tab for Mempool - api-docs.tab.mempool - - - Returns current mempool backlog statistics. - - src/app/components/api-docs/api-docs.component.html - 629,631 - - API Docs for /api/mempool - api-docs.mempool.mempool - - - Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind. - - src/app/components/api-docs/api-docs.component.html - 646,648 - - API Docs for /api/mempool/txids - api-docs.mempool.txids - - - Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value. - - src/app/components/api-docs/api-docs.component.html - 663,664 - - API Docs for /api/mempool/recent - api-docs.mempool.recent - - - Transactions - - src/app/components/api-docs/api-docs.component.html - 674,678 - - API Docs tab for Transactions - api-docs.tab.transactions - - - Returns the ancestors and the best descendant fees for a transaction. - - src/app/components/api-docs/api-docs.component.html - 689,691 - - API Docs for /api/v1/fees/cpfp - api-docs.fees.cpfp - - - Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status. - - src/app/components/api-docs/api-docs.component.html - 705,706 - - - - Returns a transaction serialized as hex. - - src/app/components/api-docs/api-docs.component.html - 722,724 - - - - Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format. - - src/app/components/api-docs/api-docs.component.html - 739,740 - - - - Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format. - - src/app/components/api-docs/api-docs.component.html - 756,757 - - - - Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx). - - src/app/components/api-docs/api-docs.component.html - 773,774 - - - - Returns the spending status of all transaction outputs. - - src/app/components/api-docs/api-docs.component.html - 790,792 - - - - Returns a transaction as binary data. - - src/app/components/api-docs/api-docs.component.html - 807,809 - - - - Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional). - - src/app/components/api-docs/api-docs.component.html - 824,825 - - - - Returns :length of latest Bisq transactions, starting from :index. - - src/app/components/api-docs/api-docs.component.html - 842,844 - - - - Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success. - - src/app/components/api-docs/api-docs.component.html - 859,860 - - - - Websocket - - src/app/components/api-docs/api-docs.component.html - 870,874 - - API Docs tab for Websocket - api-docs.tab.websocket - - - Default push: action: 'want', data: ['blocks', ...] to express what you want pushed. Available: blocks, mempool-blocks, live-2h-chart, and stats.Push transactions related to address: 'track-address': '3PbJ...bF9B' to receive all new transactions containing that address as input or output. Returns an array of transactions. address-transactions for new mempool transactions, and block-transactions for new block confirmed transactions. - - src/app/components/api-docs/api-docs.component.html - 879,880 - - api-docs.websocket.websocket - - - Privacy Policy - - src/app/components/api-docs/api-docs.component.html - 895,900 - - - src/app/dashboard/dashboard.component.html - 152,154 - - Privacy Policy - shared.privacy-policy - - - API - - src/app/components/api-docs/api-docs.component.ts - 27 - - - src/app/components/bisq-master-page/bisq-master-page.component.html - 42,44 - - - src/app/components/liquid-master-page/liquid-master-page.component.html - 47,49 - - - src/app/components/master-page/master-page.component.html - 61,63 - - - - Code Example - - src/app/components/api-docs/code-template.component.html - 6,7 - - - src/app/components/api-docs/code-template.component.html - 13,14 - - - src/app/components/api-docs/code-template.component.html - 29,30 - - API Docs code example - - - Install Package - - src/app/components/api-docs/code-template.component.html - 23,24 - - API Docs install lib - - - Response - - src/app/components/api-docs/code-template.component.html - 36,37 - - API Docs API response - Asset @@ -2553,7 +1700,7 @@ Stats src/app/components/bisq-master-page/bisq-master-page.component.html - 39,41 + 39,42 src/app/components/master-page/master-page.component.html @@ -2561,6 +1708,18 @@ master-page.stats + + Docs + + src/app/components/bisq-master-page/bisq-master-page.component.html + 42,45 + + + src/app/components/liquid-master-page/liquid-master-page.component.html + 47,50 + + master-page.docs + Next Block @@ -2597,7 +1756,7 @@ Size src/app/components/block/block.component.html - 64,65 + 64,66 src/app/components/latest-blocks/latest-blocks.component.html @@ -2609,11 +1768,11 @@ src/app/components/mempool-graph/mempool-graph.component.ts - 264 + 257 src/app/dashboard/dashboard.component.html - 92,95 + 94,97 block.size @@ -2621,7 +1780,7 @@ Weight src/app/components/block/block.component.html - 68,69 + 68,70 block.weight @@ -2645,11 +1804,11 @@ src/app/components/blockchain-blocks/blockchain-blocks.component.html - 10,13 + 11,14 src/app/components/blockchain-blocks/blockchain-blocks.component.html - 13,15 + 14,16 src/app/components/fees-box/fees-box.component.html @@ -2673,39 +1832,39 @@ src/app/components/mempool-blocks/mempool-blocks.component.html - 9,12 + 10,13 src/app/components/mempool-blocks/mempool-blocks.component.html - 12,14 + 13,15 src/app/components/transaction/transaction.component.html - 171,172 + 169,170 src/app/components/transaction/transaction.component.html - 184,185 + 182,183 src/app/components/transaction/transaction.component.html - 393,396 + 391,394 src/app/components/transaction/transaction.component.html - 404,406 + 402,404 src/app/components/transactions-list/transactions-list.component.html - 218 + 231 src/app/dashboard/dashboard.component.html - 128,132 + 130,134 src/app/dashboard/dashboard.component.html - 183,187 + 185,189 sat/vB shared.sat-vbyte @@ -2755,7 +1914,7 @@ src/app/components/block/block.component.html - 102,105 + 102,106 Total subsidy and fees in a block block.subsidy-and-fees @@ -2816,7 +1975,7 @@ src/app/components/transaction/transaction.component.html - 199,203 + 197,201 Transaction Details transaction.details @@ -2825,7 +1984,7 @@ Error loading block data. src/app/components/block/block.component.html - 256,264 + 256,266 block.error.loading-block-data @@ -2843,6 +2002,796 @@ 15 + + API service + + src/app/components/docs/api-docs.component.html + 12,14 + + api-docs.title + + + Endpoint + + src/app/components/docs/api-docs.component.html + 32,33 + + + src/app/components/docs/api-docs.component.html + 49,50 + + + src/app/components/docs/api-docs.component.html + 62,63 + + + src/app/components/docs/api-docs.component.html + 75,76 + + + src/app/components/docs/api-docs.component.html + 88,89 + + + src/app/components/docs/api-docs.component.html + 101,102 + + + src/app/components/docs/api-docs.component.html + 114,115 + + + src/app/components/docs/api-docs.component.html + 127,128 + + + src/app/components/docs/api-docs.component.html + 140,141 + + + src/app/components/docs/api-docs.component.html + 157,158 + + + src/app/components/docs/api-docs.component.html + 174,175 + + + src/app/components/docs/api-docs.component.html + 187,188 + + + src/app/components/docs/api-docs.component.html + 200,201 + + + src/app/components/docs/api-docs.component.html + 213,214 + + + src/app/components/docs/api-docs.component.html + 226,227 + + + src/app/components/docs/api-docs.component.html + 243,244 + + + src/app/components/docs/api-docs.component.html + 268,269 + + + src/app/components/docs/api-docs.component.html + 285,286 + + + src/app/components/docs/api-docs.component.html + 298,299 + + + src/app/components/docs/api-docs.component.html + 311,312 + + + src/app/components/docs/api-docs.component.html + 324,325 + + + src/app/components/docs/api-docs.component.html + 337,338 + + + src/app/components/docs/api-docs.component.html + 350,351 + + + src/app/components/docs/api-docs.component.html + 363,364 + + + src/app/components/docs/api-docs.component.html + 376,377 + + + src/app/components/docs/api-docs.component.html + 389,390 + + + src/app/components/docs/api-docs.component.html + 402,403 + + + src/app/components/docs/api-docs.component.html + 415,416 + + + src/app/components/docs/api-docs.component.html + 428,429 + + + src/app/components/docs/api-docs.component.html + 445,446 + + + src/app/components/docs/api-docs.component.html + 458,459 + + + src/app/components/docs/api-docs.component.html + 475,476 + + + src/app/components/docs/api-docs.component.html + 488,489 + + + src/app/components/docs/api-docs.component.html + 501,502 + + + src/app/components/docs/api-docs.component.html + 518,519 + + + src/app/components/docs/api-docs.component.html + 531,532 + + + src/app/components/docs/api-docs.component.html + 544,545 + + + src/app/components/docs/api-docs.component.html + 557,558 + + + src/app/components/docs/api-docs.component.html + 570,571 + + + src/app/components/docs/api-docs.component.html + 583,584 + + + src/app/components/docs/api-docs.component.html + 596,597 + + + src/app/components/docs/api-docs.component.html + 609,610 + + + src/app/components/docs/api-docs.component.html + 622,623 + + + src/app/components/docs/api-docs.component.html + 635,636 + + + src/app/components/docs/api-docs.component.html + 648,651 + + + src/app/components/docs/api-docs.component.html + 666,669 + + Api docs endpoint + + + Description + + src/app/components/docs/api-docs.component.html + 36,37 + + + src/app/components/docs/api-docs.component.html + 53,54 + + + src/app/components/docs/api-docs.component.html + 66,67 + + + src/app/components/docs/api-docs.component.html + 79,80 + + + src/app/components/docs/api-docs.component.html + 92,94 + + + src/app/components/docs/api-docs.component.html + 105,106 + + + src/app/components/docs/api-docs.component.html + 118,119 + + + src/app/components/docs/api-docs.component.html + 131,132 + + + src/app/components/docs/api-docs.component.html + 144,145 + + + src/app/components/docs/api-docs.component.html + 161,162 + + + src/app/components/docs/api-docs.component.html + 178,179 + + + src/app/components/docs/api-docs.component.html + 191,192 + + + src/app/components/docs/api-docs.component.html + 204,205 + + + src/app/components/docs/api-docs.component.html + 217,218 + + + src/app/components/docs/api-docs.component.html + 230,231 + + + src/app/components/docs/api-docs.component.html + 247,248 + + + src/app/components/docs/api-docs.component.html + 259,260 + + + src/app/components/docs/api-docs.component.html + 272,273 + + + src/app/components/docs/api-docs.component.html + 289,290 + + + src/app/components/docs/api-docs.component.html + 302,303 + + + src/app/components/docs/api-docs.component.html + 315,316 + + + src/app/components/docs/api-docs.component.html + 328,329 + + + src/app/components/docs/api-docs.component.html + 341,342 + + + src/app/components/docs/api-docs.component.html + 354,355 + + + src/app/components/docs/api-docs.component.html + 367,369 + + + src/app/components/docs/api-docs.component.html + 380,381 + + + src/app/components/docs/api-docs.component.html + 393,394 + + + src/app/components/docs/api-docs.component.html + 406,407 + + + src/app/components/docs/api-docs.component.html + 419,420 + + + src/app/components/docs/api-docs.component.html + 432,433 + + + src/app/components/docs/api-docs.component.html + 449,450 + + + src/app/components/docs/api-docs.component.html + 462,463 + + + src/app/components/docs/api-docs.component.html + 479,480 + + + src/app/components/docs/api-docs.component.html + 492,493 + + + src/app/components/docs/api-docs.component.html + 505,506 + + + src/app/components/docs/api-docs.component.html + 522,523 + + + src/app/components/docs/api-docs.component.html + 535,536 + + + src/app/components/docs/api-docs.component.html + 548,549 + + + src/app/components/docs/api-docs.component.html + 561,562 + + + src/app/components/docs/api-docs.component.html + 574,575 + + + src/app/components/docs/api-docs.component.html + 587,588 + + + src/app/components/docs/api-docs.component.html + 600,601 + + + src/app/components/docs/api-docs.component.html + 613,614 + + + src/app/components/docs/api-docs.component.html + 626,627 + + + src/app/components/docs/api-docs.component.html + 639,640 + + + src/app/components/docs/api-docs.component.html + 652,653 + + + src/app/components/docs/api-docs.component.html + 670,671 + + + + Returns details about difficulty adjustment. + + src/app/components/docs/api-docs.component.html + 37,39 + + + + Provides list of available currencies for a given base currency. + + src/app/components/docs/api-docs.component.html + 54,56 + + + + Provides list of open offer prices for a single market. + + src/app/components/docs/api-docs.component.html + 67,69 + + + + Provides hi/low/open/close data for a given market. This can be used to generate a candlestick chart. + + src/app/components/docs/api-docs.component.html + 80,82 + + + + Provides list of available markets. + + src/app/components/docs/api-docs.component.html + 93,95 + + + + Provides list of open offer details for a single market. + + src/app/components/docs/api-docs.component.html + 106,108 + + + + Provides 24 hour price ticker for single market or all markets + + src/app/components/docs/api-docs.component.html + 119,121 + + + + Provides list of completed trades for a single market. + + src/app/components/docs/api-docs.component.html + 132,134 + + + + Provides periodic volume data in terms of base currency for one or all markets. + + src/app/components/docs/api-docs.component.html + 145,147 + + + + Returns statistics about all Bisq transactions. + + src/app/components/docs/api-docs.component.html + 162,164 + + + + Returns details about an address. Available fields: address, chain_stats, and mempool_stats. chain,mempool_stats each contain an object with tx_count, funded_txo_count, funded_txo_sum, spent_txo_count, and spent_txo_sum. + + src/app/components/docs/api-docs.component.html + 179,180 + + + + Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using :last_seen_txid (see below). + + src/app/components/docs/api-docs.component.html + 192,193 + + + + Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query. + + src/app/components/docs/api-docs.component.html + 205,207 + + + + Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging). + + src/app/components/docs/api-docs.component.html + 218,220 + + + + Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: txid, vout, value, and status (with the status of the funding tx).There is also a valuecommitment field that may appear in place of value, plus the following additional fields: asset/assetcommitment, nonce/noncecommitment, surjection_proof, and range_proof. + + src/app/components/docs/api-docs.component.html + 231,233 + + + + Returns information about a Liquid asset. + + src/app/components/docs/api-docs.component.html + 248,250 + + + + Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset. + + src/app/components/docs/api-docs.component.html + 260,262 + + + + Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units. + + src/app/components/docs/api-docs.component.html + 273,275 + + + + Returns details about a block. Available fields: id, height, version, timestamp, bits, nonce, merkle_root, tx_count, size, weight,proof, and previousblockhash. + + src/app/components/docs/api-docs.component.html + 290,291 + + + + Returns the hex-encoded block header. + + src/app/components/docs/api-docs.component.html + 303,305 + + + + Returns the hash of the block currently at :height. + + src/app/components/docs/api-docs.component.html + 316,317 + + + + Returns the raw block representation in binary. + + src/app/components/docs/api-docs.component.html + 329,331 + + + + Returns the confirmation status of a block. Available fields: in_best_chain (boolean, false for orphaned blocks), next_best (the hash of the next block, only available for blocks in the best chain). + + src/app/components/docs/api-docs.component.html + 342,343 + + + + Returns the height of the last block. + + src/app/components/docs/api-docs.component.html + 355,357 + + + + Returns the hash of the last block. + + src/app/components/docs/api-docs.component.html + 368,370 + + + + Returns the transaction at index :index within the specified block. + + src/app/components/docs/api-docs.component.html + 381,382 + + + + Returns a list of all txids in the block. + + src/app/components/docs/api-docs.component.html + 394,396 + + + + Returns a list of transactions in the block (up to 25 transactions beginning at start_index). Transactions returned here do not have the status field, since all the transactions share the same block and confirmation status. + + src/app/components/docs/api-docs.component.html + 407,408 + + + + Returns the 10 newest blocks starting at the tip or at :start_height if specified. + + src/app/components/docs/api-docs.component.html + 420,421 + + + src/app/components/docs/api-docs.component.html + 433,434 + + + + Returns current mempool as projected blocks. + + src/app/components/docs/api-docs.component.html + 450,452 + + API Docs for /api/v1/fees/mempool-blocks + api-docs.fees.mempool-blocks + + + Returns our currently suggested fees for new transactions. + + src/app/components/docs/api-docs.component.html + 463,465 + + API Docs for /api/v1/fees/recommended + api-docs.fees.recommended + + + Returns current mempool backlog statistics. + + src/app/components/docs/api-docs.component.html + 480,482 + + API Docs for /api/mempool + api-docs.mempool.mempool + + + Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind. + + src/app/components/docs/api-docs.component.html + 493,495 + + API Docs for /api/mempool/txids + api-docs.mempool.txids + + + Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: txid, fee, vsize, and value. + + src/app/components/docs/api-docs.component.html + 506,507 + + API Docs for /api/mempool/recent + api-docs.mempool.recent + + + Returns the ancestors and the best descendant fees for a transaction. + + src/app/components/docs/api-docs.component.html + 523,525 + + API Docs for /api/v1/fees/cpfp + api-docs.fees.cpfp + + + Returns details about a transaction. Available fields: txid, version, locktime, size, weight, fee, vin, vout, and status. + + src/app/components/docs/api-docs.component.html + 536,537 + + + + Returns a transaction serialized as hex. + + src/app/components/docs/api-docs.component.html + 549,551 + + + + Returns a merkle inclusion proof for the transaction using bitcoind's merkleblock format. + + src/app/components/docs/api-docs.component.html + 562,563 + + + + Returns a merkle inclusion proof for the transaction using Electrum's blockchain.transaction.get_merkle format. + + src/app/components/docs/api-docs.component.html + 575,576 + + + + Returns the spending status of a transaction output. Available fields: spent (boolean), txid (optional), vin (optional), and status (optional, the status of the spending tx). + + src/app/components/docs/api-docs.component.html + 588,589 + + + + Returns the spending status of all transaction outputs. + + src/app/components/docs/api-docs.component.html + 601,603 + + + + Returns a transaction as binary data. + + src/app/components/docs/api-docs.component.html + 614,616 + + + + Returns the confirmation status of a transaction. Available fields: confirmed (boolean), block_height (optional), and block_hash (optional). + + src/app/components/docs/api-docs.component.html + 627,628 + + + + Returns :length of latest Bisq transactions, starting from :index. + + src/app/components/docs/api-docs.component.html + 640,642 + + + + Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The txid will be returned on success. + + src/app/components/docs/api-docs.component.html + 653,654 + + + + Default push: action: 'want', data: ['blocks', ...] to express what you want pushed. Available: blocks, mempool-blocks, live-2h-chart, and stats.Push transactions related to address: 'track-address': '3PbJ...bF9B' to receive all new transactions containing that address as input or output. Returns an array of transactions. address-transactions for new mempool transactions, and block-transactions for new block confirmed transactions. + + src/app/components/docs/api-docs.component.html + 671,672 + + api-docs.websocket.websocket + + + API + + src/app/components/docs/api-docs.component.ts + 42 + + + + Code Example + + src/app/components/docs/code-template.component.html + 6,7 + + + src/app/components/docs/code-template.component.html + 13,14 + + + src/app/components/docs/code-template.component.html + 29,30 + + API Docs code example + + + Install Package + + src/app/components/docs/code-template.component.html + 23,24 + + API Docs install lib + + + Response + + src/app/components/docs/code-template.component.html + 36,37 + + API Docs API response + + + Documentation + + src/app/components/docs/docs.component.html + 4 + + + src/app/components/master-page/master-page.component.html + 61,64 + + documentation.title + + + Privacy Policy + + src/app/components/docs/docs.component.html + 35 + + + src/app/dashboard/dashboard.component.html + 154,156 + + Privacy Policy + shared.privacy-policy + Low priority @@ -2895,7 +2844,7 @@ src/app/dashboard/dashboard.component.html - 219,221 + 221,224 dashboard.backend-is-synchronizing @@ -2903,11 +2852,11 @@ vB/s src/app/components/footer/footer.component.html - 11,15 + 11,16 src/app/dashboard/dashboard.component.html - 224,230 + 226,232 vB/s shared.vbytes-per-second @@ -2916,11 +2865,11 @@ Unconfirmed src/app/components/footer/footer.component.html - 16,17 + 16,18 src/app/dashboard/dashboard.component.html - 187,188 + 189,190 Unconfirmed count dashboard.unconfirmed @@ -2935,30 +2884,33 @@ dashboard.mempool-size - blocks + blocks src/app/components/footer/footer.component.html 22,23 src/app/components/mempool-blocks/mempool-blocks.component.html - 31,32 + 32,33 src/app/dashboard/dashboard.component.html - 240,241 + 242,243 shared.blocks - block + block src/app/components/footer/footer.component.html 23,24 src/app/dashboard/dashboard.component.html - 241,242 + 243,244 shared.block @@ -2970,10 +2922,17 @@ src/app/dashboard/dashboard.component.html - 90,91 + 92,93 latest-blocks.mined + + Blocks + + src/app/components/latest-blocks/latest-blocks.component.ts + 39 + + Graphs @@ -3043,14 +3002,14 @@ Range src/app/components/mempool-graph/mempool-graph.component.ts - 263 + 256 Sum src/app/components/mempool-graph/mempool-graph.component.ts - 265 + 258 @@ -3087,7 +3046,7 @@ src/app/dashboard/dashboard.component.html - 154,160 + 156,162 Broadcast Transaction shared.broadcast-transaction @@ -3100,7 +3059,7 @@ src/app/components/transaction/transaction.component.html - 240,241 + 238,239 transaction.hex @@ -3184,7 +3143,7 @@ Invert src/app/components/statistics/statistics.component.html - 73 + 62 statistics.component-invert.title @@ -3192,7 +3151,7 @@ Transaction vBytes per second (vB/s) src/app/components/statistics/statistics.component.html - 98 + 87 statistics.transaction-vbytes-per-second @@ -3401,11 +3360,11 @@ Unconfirmed src/app/components/transaction/transaction.component.html - 34,41 + 32,39 src/app/components/transactions-list/transactions-list.component.html - 229,233 + 242,246 Transaction unconfirmed state transaction.unconfirmed @@ -3414,7 +3373,7 @@ Confirmed src/app/components/transaction/transaction.component.html - 67,68 + 65,66 Transaction Confirmed state transaction.confirmed @@ -3423,7 +3382,7 @@ First seen src/app/components/transaction/transaction.component.html - 103,104 + 101,102 Transaction first seen transaction.first-seen @@ -3432,7 +3391,7 @@ ETA src/app/components/transaction/transaction.component.html - 109,111 + 108,109 Transaction ETA transaction.eta @@ -3441,7 +3400,7 @@ In several hours (or more) src/app/components/transaction/transaction.component.html - 116,119 + 114,117 Transaction ETA in several hours or more transaction.eta.in-several-hours @@ -3450,11 +3409,11 @@ Virtual size src/app/components/transaction/transaction.component.html - 155,157 + 153,155 src/app/components/transaction/transaction.component.html - 218,221 + 216,219 Transaction Virtual Size transaction.vsize @@ -3463,11 +3422,11 @@ Fee rate src/app/components/transaction/transaction.component.html - 156,160 + 154,158 src/app/components/transaction/transaction.component.html - 391,393 + 389,391 Transaction fee rate transaction.fee-rate @@ -3476,7 +3435,7 @@ Descendant src/app/components/transaction/transaction.component.html - 163,165 + 161,163 Descendant transaction.descendant @@ -3485,7 +3444,7 @@ Ancestor src/app/components/transaction/transaction.component.html - 177,179 + 175,177 Transaction Ancestor transaction.ancestor @@ -3494,7 +3453,7 @@ Size src/app/components/transaction/transaction.component.html - 214,217 + 212,215 Transaction Size transaction.size @@ -3503,7 +3462,7 @@ Weight src/app/components/transaction/transaction.component.html - 222,225 + 220,223 Transaction Weight transaction.weight @@ -3512,7 +3471,7 @@ Locktime src/app/components/transaction/transaction.component.html - 236,238 + 234,236 transaction.locktime @@ -3520,7 +3479,7 @@ Transaction not found. src/app/components/transaction/transaction.component.html - 367,368 + 365,366 transaction.error.transaction-not-found @@ -3528,7 +3487,7 @@ Waiting for it to appear in the mempool... src/app/components/transaction/transaction.component.html - 368,372 + 366,371 transaction.error.waiting-for-it-to-appear @@ -3536,7 +3495,7 @@ Fee src/app/components/transaction/transaction.component.html - 387,388 + 386 Transaction fee transaction.fee @@ -3545,7 +3504,7 @@ sat src/app/components/transaction/transaction.component.html - 388,391 + 386,389 Transaction Fee sat transaction.fee.sat @@ -3554,7 +3513,7 @@ Effective fee rate src/app/components/transaction/transaction.component.html - 401,404 + 399,402 Effective transaction fee rate transaction.effective-fee-rate @@ -3563,7 +3522,7 @@ Coinbase src/app/components/transactions-list/transactions-list.component.html - 44 + 51 transactions-list.coinbase @@ -3571,7 +3530,7 @@ (Newly Generated Coins) src/app/components/transactions-list/transactions-list.component.html - 44 + 51 transactions-list.newly-generated-coins @@ -3579,7 +3538,7 @@ Peg-in src/app/components/transactions-list/transactions-list.component.html - 46,48 + 53,55 transactions-list.peg-in @@ -3587,7 +3546,7 @@ ScriptSig (ASM) src/app/components/transactions-list/transactions-list.component.html - 79,81 + 86,88 ScriptSig (ASM) transactions-list.scriptsig.asm @@ -3596,7 +3555,7 @@ ScriptSig (HEX) src/app/components/transactions-list/transactions-list.component.html - 83,85 + 90,93 ScriptSig (HEX) transactions-list.scriptsig.hex @@ -3605,7 +3564,7 @@ Witness src/app/components/transactions-list/transactions-list.component.html - 88,89 + 95,97 transactions-list.witness @@ -3613,7 +3572,7 @@ P2SH redeem script src/app/components/transactions-list/transactions-list.component.html - 92,93 + 99,100 transactions-list.p2sh-redeem-script @@ -3621,7 +3580,7 @@ P2WSH witness script src/app/components/transactions-list/transactions-list.component.html - 96,97 + 103,104 transactions-list.p2wsh-witness-script @@ -3629,7 +3588,7 @@ nSequence src/app/components/transactions-list/transactions-list.component.html - 100,101 + 107,109 transactions-list.nsequence @@ -3637,7 +3596,7 @@ Previous output script src/app/components/transactions-list/transactions-list.component.html - 105,106 + 112,113 transactions-list.previous-output-script @@ -3645,7 +3604,7 @@ Previous output type src/app/components/transactions-list/transactions-list.component.html - 109,110 + 116,117 transactions-list.previous-output-type @@ -3653,19 +3612,19 @@ Load all src/app/components/transactions-list/transactions-list.component.html - 120,123 + 127,130 src/app/components/transactions-list/transactions-list.component.html - 208,211 + 221,224 transactions-list.load-all - Peg-out to + Peg-out to src/app/components/transactions-list/transactions-list.component.html - 139,140 + 146,147 transactions-list.peg-out-to @@ -3673,7 +3632,7 @@ ScriptPubKey (ASM) src/app/components/transactions-list/transactions-list.component.html - 186,188 + 199,201 ScriptPubKey (ASM) transactions-list.scriptpubkey.asm @@ -3682,7 +3641,7 @@ ScriptPubKey (HEX) src/app/components/transactions-list/transactions-list.component.html - 190,192 + 203,206 ScriptPubKey (HEX) transactions-list.scriptpubkey.hex @@ -3691,7 +3650,7 @@ data src/app/components/transactions-list/transactions-list.component.html - 194,195 + 207,209 transactions-list.vout.scriptpubkey-type.data @@ -3699,7 +3658,7 @@ sat src/app/components/transactions-list/transactions-list.component.html - 218 + 231,232 sat shared.sat @@ -3840,7 +3799,7 @@ Latest blocks src/app/dashboard/dashboard.component.html - 86,89 + 88,91 dashboard.latest-blocks @@ -3848,11 +3807,11 @@ TXs src/app/dashboard/dashboard.component.html - 91,93 + 94,95 src/app/dashboard/dashboard.component.html - 189,193 + 191,195 dashboard.latest-blocks.transaction-count @@ -3860,7 +3819,7 @@ Latest transactions src/app/dashboard/dashboard.component.html - 115,118 + 117,120 dashboard.latest-transactions @@ -3868,7 +3827,7 @@ USD src/app/dashboard/dashboard.component.html - 120,121 + 123,124 dashboard.latest-transactions.USD @@ -3876,7 +3835,7 @@ Fee src/app/dashboard/dashboard.component.html - 121,124 + 124,126 dashboard.latest-transactions.fee @@ -3884,7 +3843,7 @@ Expand src/app/dashboard/dashboard.component.html - 142,143 + 144,145 dashboard.expand @@ -3892,7 +3851,7 @@ Collapse src/app/dashboard/dashboard.component.html - 143,147 + 145,151 dashboard.collapse @@ -3900,7 +3859,7 @@ Minimum fee src/app/dashboard/dashboard.component.html - 180,181 + 182,183 Minimum mempool fee dashboard.minimum-fee @@ -3909,7 +3868,7 @@ Purging src/app/dashboard/dashboard.component.html - 181,182 + 183,184 Purgin below fee dashboard.purging @@ -3918,7 +3877,7 @@ Memory usage src/app/dashboard/dashboard.component.html - 193,194 + 195,196 Memory usage dashboard.memory-usage @@ -3927,7 +3886,7 @@ L-BTC in circulation src/app/dashboard/dashboard.component.html - 207,208 + 209,211 dashboard.lbtc-pegs-in-circulation @@ -3935,7 +3894,7 @@ Incoming transactions src/app/dashboard/dashboard.component.html - 216,217 + 218,219 dashboard.incoming-transactions @@ -3943,7 +3902,7 @@ Difficulty Adjustment src/app/dashboard/dashboard.component.html - 231,234 + 233,237 dashboard.difficulty-adjustment @@ -3951,11 +3910,11 @@ Remaining src/app/dashboard/dashboard.component.html - 237,239 + 239,241 src/app/dashboard/dashboard.component.html - 288,291 + 290,293 difficulty-box.remaining @@ -3963,11 +3922,11 @@ Estimate src/app/dashboard/dashboard.component.html - 246,247 + 248,249 src/app/dashboard/dashboard.component.html - 295,298 + 297,300 difficulty-box.estimate @@ -3975,7 +3934,7 @@ Previous src/app/dashboard/dashboard.component.html - 261,263 + 263,265 difficulty-box.previous @@ -3983,11 +3942,11 @@ Current Period src/app/dashboard/dashboard.component.html - 273,274 + 275,276 src/app/dashboard/dashboard.component.html - 302,305 + 304,307 difficulty-box.current-period diff --git a/frontend/src/resources/profile/blockstream.svg b/frontend/src/resources/profile/blockstream.svg new file mode 100644 index 000000000..6dc32eab9 --- /dev/null +++ b/frontend/src/resources/profile/blockstream.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index afc16ec52..e870f32e8 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -555,7 +555,7 @@ html:lang(ru) .card-title { } .tx-wrapper-tooltip-chart-advanced { - width: 115px; + width: 140px; .indicator-container { .indicator { margin-right: 5px;