From 5202e669ced164ce9d03eee84a3457362f0838cd Mon Sep 17 00:00:00 2001 From: Antoni Spaanderman <56turtle56@gmail.com> Date: Tue, 18 Jan 2022 22:25:38 +0100 Subject: [PATCH 01/63] outputs of genesis coinbase are always unspent --- backend/src/api/bitcoin/bitcoin-api.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index 79505d5c3..c23e86ee0 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -106,10 +106,16 @@ class BitcoinApi implements AbstractBitcoinApi { const outSpends: IEsploraApi.Outspend[] = []; const tx = await this.$getRawTransaction(txId, true, false); for (let i = 0; i < tx.vout.length; i++) { - const txOut = await this.bitcoindClient.getTxOut(txId, i); - outSpends.push({ - spent: txOut === null, - }); + if (tx.status && tx.status.block_height == 0) { + outSpends.push({ + spent: false + }); + } else { + const txOut = await this.bitcoindClient.getTxOut(txId, i); + outSpends.push({ + spent: txOut === null, + }); + } } return outSpends; } From 49689d8807051b155aad55fc3c390574a6f913d7 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Wed, 19 Jan 2022 18:50:52 +0900 Subject: [PATCH 02/63] Import mining pools into the database - Increment db schema to 3 --- backend/src/api/database-migration.ts | 20 ++++- backend/src/api/pools-parser.ts | 118 ++++++++++++++++++++++++++ backend/src/index.ts | 2 + 3 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 backend/src/api/pools-parser.ts diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 2ac97636e..9fdd4d210 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -3,10 +3,10 @@ import config from '../config'; import { DB } from '../database'; import logger from '../logger'; -const sleep = (ms: number) => new Promise( res => setTimeout(res, ms)); +const sleep = (ms: number) => new Promise(res => setTimeout(res, ms)); class DatabaseMigration { - private static currentVersion = 2; + private static currentVersion = 3; private queryTimeout = 120000; private statisticsAddedIndexed = false; @@ -83,6 +83,9 @@ class DatabaseMigration { if (databaseSchemaVersion < 2 && this.statisticsAddedIndexed === false) { await this.$executeQuery(connection, `CREATE INDEX added ON statistics (added);`); } + if (databaseSchemaVersion < 3) { + await this.$executeQuery(connection, this.getCreatePoolsTableQuery(), await this.$checkIfTableExists('pools')); + } connection.release(); } catch (e) { connection.release(); @@ -335,6 +338,17 @@ class DatabaseMigration { final_tx int(11) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; } + + private getCreatePoolsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS pools ( + id int(11) NOT NULL AUTO_INCREMENT, + name varchar(50) NOT NULL, + link varchar(255) NOT NULL, + addresses text NOT NULL, + regexes text NOT NULL, + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`; + } } -export default new DatabaseMigration(); +export default new DatabaseMigration(); \ No newline at end of file diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts new file mode 100644 index 000000000..c17336288 --- /dev/null +++ b/backend/src/api/pools-parser.ts @@ -0,0 +1,118 @@ +import {readFileSync} from 'fs'; +import { DB } from '../database'; +import logger from '../logger'; + +interface Pool { + name: string, + link: string, + regexes: string[], + addresses: string[], +} + +class PoolsParser { + /** + * Parse the pools.json file, consolidate the data and dump it into the database + */ + public async migratePoolsJson() { + logger.info('Importing pools.json to the database'); + let connection = await DB.pool.getConnection(); + + // Check if the pools table does not have data already, for now we do not support updating it + // but that will come in a later version + let [rows] = await connection.query({ sql: 'SELECT count(id) as count from pools;', timeout: 120000 }); + if (rows[0].count !== 0) { + logger.info('Pools table already contain data, updating it is not yet supported, skipping.'); + connection.release(); + return; + } + + logger.info('Open ../frontend/cypress/fixtures/pools.json'); + const fileContent: string = readFileSync('../frontend/cypress/fixtures/pools.json','utf8'); + const poolsJson: object = JSON.parse(fileContent); + + // First we save every entries without paying attention to pool duplication + let poolsDuplicated: Pool[] = []; + + logger.info('Parse coinbase_tags'); + const coinbaseTags = Object.entries(poolsJson['coinbase_tags']); + for (let i = 0; i < coinbaseTags.length; ++i) { + poolsDuplicated.push({ + 'name': (coinbaseTags[i][1]).name, + 'link': (coinbaseTags[i][1]).link, + 'regexes': [coinbaseTags[i][0]], + 'addresses': [], + }); + } + logger.info('Parse payout_addresses'); + const addressesTags = Object.entries(poolsJson['payout_addresses']); + for (let i = 0; i < addressesTags.length; ++i) { + poolsDuplicated.push({ + 'name': (addressesTags[i][1]).name, + 'link': (addressesTags[i][1]).link, + 'regexes': [], + 'addresses': [addressesTags[i][0]], + }); + } + + // Then, we find unique mining pool names + logger.info('Identify unique mining pools'); + let poolNames : string[] = []; + for (let i = 0; i < poolsDuplicated.length; ++i) { + if (poolNames.indexOf(poolsDuplicated[i].name) === -1) { + poolNames.push(poolsDuplicated[i].name); + } + } + logger.info(`Found ${poolNames.length} unique mining pools`); + + // Finally, we generate the final consolidated pools data + let finalPoolData: Pool[] = []; + for (let i = 0; i < poolNames.length; ++i) { + let allAddresses: string[] = []; + let allRegexes: string[] = []; + let match = poolsDuplicated.filter((pool: Pool) => pool.name === poolNames[i]); + + for (let y = 0; y < match.length; ++y) { + allAddresses = allAddresses.concat(match[y].addresses); + allRegexes = allRegexes.concat(match[y].regexes); + } + + finalPoolData.push({ + 'name': poolNames[i].replace("'", "''"), + 'link': match[0].link, + 'regexes': allRegexes, + 'addresses': allAddresses, + }) + } + + // Manually add the 'unknown pool' + finalPoolData.push({ + 'name': 'Unknown', + 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', + regexes: [], + addresses: [], + }) + + // Dump everything into the database + logger.info(`Insert mining pool info into the database`); + let query: string = 'INSERT INTO pools(name, link, regexes, addresses) VALUES '; + for (let i = 0; i < finalPoolData.length; ++i) { + query += `('${finalPoolData[i].name}', '${finalPoolData[i].link}', + '${JSON.stringify(finalPoolData[i].regexes)}', '${JSON.stringify(finalPoolData[i].addresses)}'),`; + } + query = query.slice(0, -1) + ';'; + + try { + await connection.query({ sql: 'DELETE FROM pools;', timeout: 120000 }); // We clear the table before insertion + await connection.query({ sql: query, timeout: 120000 }); + connection.release(); + logger.info('Import completed'); + } catch (e) { + connection.release(); + logger.info(`Unable to import pools in the database!`); + throw e; + } + } + +} + +export default new PoolsParser(); \ No newline at end of file diff --git a/backend/src/index.ts b/backend/src/index.ts index f6615d1c8..9e4dcee35 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -22,6 +22,7 @@ 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 poolsParser from './api/pools-parser'; import syncAssets from './sync-assets'; import icons from './api/liquid/icons'; import { Common } from './api/common'; @@ -88,6 +89,7 @@ class Server { await checkDbConnection(); try { await databaseMigration.$initializeOrMigrateDatabase(); + await poolsParser.migratePoolsJson(); } catch (e) { throw new Error(e instanceof Error ? e.message : 'Error'); } From 43b255bef15b41013a0d787a5d903bedebeaffa1 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 20 Jan 2022 13:53:08 +0900 Subject: [PATCH 03/63] Add pools.json to EXTERNAL_ASSETS - Now supports updating the table --- backend/mempool-config.sample.json | 4 +- backend/src/api/pools-parser.ts | 94 +++++++++++++++++++----------- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index ea656c1de..1b55f38f4 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -14,7 +14,9 @@ "MEMPOOL_BLOCKS_AMOUNT": 8, "PRICE_FEED_UPDATE_INTERVAL": 3600, "USE_SECOND_NODE_FOR_MINFEE": false, - "EXTERNAL_ASSETS": [] + "EXTERNAL_ASSETS": [ + "https://mempool.space/resources/pools.json" + ] }, "CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index c17336288..5e6a38e49 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -14,20 +14,14 @@ class PoolsParser { * Parse the pools.json file, consolidate the data and dump it into the database */ public async migratePoolsJson() { + const connection = await DB.pool.getConnection(); logger.info('Importing pools.json to the database'); - let connection = await DB.pool.getConnection(); - // Check if the pools table does not have data already, for now we do not support updating it - // but that will come in a later version - let [rows] = await connection.query({ sql: 'SELECT count(id) as count from pools;', timeout: 120000 }); - if (rows[0].count !== 0) { - logger.info('Pools table already contain data, updating it is not yet supported, skipping.'); - connection.release(); - return; - } + // Get existing pools from the db + const [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); // We clear the table before insertion - logger.info('Open ../frontend/cypress/fixtures/pools.json'); - const fileContent: string = readFileSync('../frontend/cypress/fixtures/pools.json','utf8'); + logger.info('Open ./pools.json'); + const fileContent: string = readFileSync('./pools.json','utf8'); const poolsJson: object = JSON.parse(fileContent); // First we save every entries without paying attention to pool duplication @@ -65,7 +59,8 @@ class PoolsParser { logger.info(`Found ${poolNames.length} unique mining pools`); // Finally, we generate the final consolidated pools data - let finalPoolData: Pool[] = []; + let finalPoolDataAdd: Pool[] = []; + let finalPoolDataUpdate: Pool[] = []; for (let i = 0; i < poolNames.length; ++i) { let allAddresses: string[] = []; let allRegexes: string[] = []; @@ -76,34 +71,65 @@ class PoolsParser { allRegexes = allRegexes.concat(match[y].regexes); } - finalPoolData.push({ - 'name': poolNames[i].replace("'", "''"), - 'link': match[0].link, - 'regexes': allRegexes, - 'addresses': allAddresses, - }) + const finalPoolName = poolNames[i].replace("'", "''"); // To support single quote in names when doing db queries + + if (existingPools.find((pool) => { return pool.name === poolNames[i]}) !== undefined) { + logger.debug(`Update '${finalPoolName} mining pool`); + finalPoolDataUpdate.push({ + 'name': finalPoolName, + 'link': match[0].link, + 'regexes': allRegexes, + 'addresses': allAddresses, + }) + } else { + logger.debug(`Add '${finalPoolName} mining pool`); + finalPoolDataAdd.push({ + 'name': finalPoolName, + 'link': match[0].link, + 'regexes': allRegexes, + 'addresses': allAddresses, + }) + } } // Manually add the 'unknown pool' - finalPoolData.push({ - 'name': 'Unknown', - 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', - regexes: [], - addresses: [], - }) - - // Dump everything into the database - logger.info(`Insert mining pool info into the database`); - let query: string = 'INSERT INTO pools(name, link, regexes, addresses) VALUES '; - for (let i = 0; i < finalPoolData.length; ++i) { - query += `('${finalPoolData[i].name}', '${finalPoolData[i].link}', - '${JSON.stringify(finalPoolData[i].regexes)}', '${JSON.stringify(finalPoolData[i].addresses)}'),`; + if (existingPools.find((pool) => { return pool.name === "Uknown"}) !== undefined) { + finalPoolDataAdd.push({ + 'name': 'Unknown', + 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', + regexes: [], + addresses: [], + }) + } + + logger.info(`Update pools table now`); + + // Add new mining pools into the database + let queryAdd: string = 'INSERT INTO pools(name, link, regexes, addresses) VALUES '; + for (let i = 0; i < finalPoolDataAdd.length; ++i) { + queryAdd += `('${finalPoolDataAdd[i].name}', '${finalPoolDataAdd[i].link}', + '${JSON.stringify(finalPoolDataAdd[i].regexes)}', '${JSON.stringify(finalPoolDataAdd[i].addresses)}'),`; + } + queryAdd = queryAdd.slice(0, -1) + ';'; + + // Add new mining pools into the database + let updateQueries: string[] = []; + for (let i = 0; i < finalPoolDataUpdate.length; ++i) { + updateQueries.push(` + UPDATE pools + SET name='${finalPoolDataUpdate[i].name}', link='${finalPoolDataUpdate[i].link}', + regexes='${JSON.stringify(finalPoolDataUpdate[i].regexes)}', addresses='${JSON.stringify(finalPoolDataUpdate[i].addresses)}' + WHERE name='${finalPoolDataUpdate[i].name}' + ;`); } - query = query.slice(0, -1) + ';'; try { - await connection.query({ sql: 'DELETE FROM pools;', timeout: 120000 }); // We clear the table before insertion - await connection.query({ sql: query, timeout: 120000 }); + if (finalPoolDataAdd.length > 0) { + await connection.query({ sql: queryAdd, timeout: 120000 }); + } + updateQueries.forEach(async query => { + await connection.query({ sql: query, timeout: 120000 }); + }); connection.release(); logger.info('Import completed'); } catch (e) { From 16f13fff3280539304213d80fcb15b7390a1b924 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 20 Jan 2022 16:34:14 +0900 Subject: [PATCH 04/63] Fix linter issues and typo --- backend/src/api/pools-parser.ts | 42 ++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 5e6a38e49..da048f2d3 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -3,10 +3,10 @@ import { DB } from '../database'; import logger from '../logger'; interface Pool { - name: string, - link: string, - regexes: string[], - addresses: string[], + name: string; + link: string; + regexes: string[]; + addresses: string[]; } class PoolsParser { @@ -18,14 +18,14 @@ class PoolsParser { logger.info('Importing pools.json to the database'); // Get existing pools from the db - const [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); // We clear the table before insertion + const [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); logger.info('Open ./pools.json'); - const fileContent: string = readFileSync('./pools.json','utf8'); + const fileContent: string = readFileSync('./pools.json', 'utf8'); const poolsJson: object = JSON.parse(fileContent); // First we save every entries without paying attention to pool duplication - let poolsDuplicated: Pool[] = []; + const poolsDuplicated: Pool[] = []; logger.info('Parse coinbase_tags'); const coinbaseTags = Object.entries(poolsJson['coinbase_tags']); @@ -50,7 +50,7 @@ class PoolsParser { // Then, we find unique mining pool names logger.info('Identify unique mining pools'); - let poolNames : string[] = []; + const poolNames: string[] = []; for (let i = 0; i < poolsDuplicated.length; ++i) { if (poolNames.indexOf(poolsDuplicated[i].name) === -1) { poolNames.push(poolsDuplicated[i].name); @@ -59,47 +59,47 @@ class PoolsParser { logger.info(`Found ${poolNames.length} unique mining pools`); // Finally, we generate the final consolidated pools data - let finalPoolDataAdd: Pool[] = []; - let finalPoolDataUpdate: Pool[] = []; + const finalPoolDataAdd: Pool[] = []; + const finalPoolDataUpdate: Pool[] = []; for (let i = 0; i < poolNames.length; ++i) { let allAddresses: string[] = []; let allRegexes: string[] = []; - let match = poolsDuplicated.filter((pool: Pool) => pool.name === poolNames[i]); + const match = poolsDuplicated.filter((pool: Pool) => pool.name === poolNames[i]); for (let y = 0; y < match.length; ++y) { allAddresses = allAddresses.concat(match[y].addresses); allRegexes = allRegexes.concat(match[y].regexes); } - const finalPoolName = poolNames[i].replace("'", "''"); // To support single quote in names when doing db queries + const finalPoolName = poolNames[i].replace(`'`, `''`); // To support single quote in names when doing db queries - if (existingPools.find((pool) => { return pool.name === poolNames[i]}) !== undefined) { - logger.debug(`Update '${finalPoolName} mining pool`); + if (existingPools.find((pool) => pool.name === poolNames[i]) !== undefined) { + logger.debug(`Update '${finalPoolName}' mining pool`); finalPoolDataUpdate.push({ 'name': finalPoolName, 'link': match[0].link, 'regexes': allRegexes, 'addresses': allAddresses, - }) + }); } else { - logger.debug(`Add '${finalPoolName} mining pool`); + logger.debug(`Add '${finalPoolName}' mining pool`); finalPoolDataAdd.push({ 'name': finalPoolName, 'link': match[0].link, 'regexes': allRegexes, 'addresses': allAddresses, - }) + }); } } // Manually add the 'unknown pool' - if (existingPools.find((pool) => { return pool.name === "Uknown"}) !== undefined) { + if (existingPools.find((pool) => pool.name === 'Unknown') !== undefined) { finalPoolDataAdd.push({ 'name': 'Unknown', 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', regexes: [], addresses: [], - }) + }); } logger.info(`Update pools table now`); @@ -113,7 +113,7 @@ class PoolsParser { queryAdd = queryAdd.slice(0, -1) + ';'; // Add new mining pools into the database - let updateQueries: string[] = []; + const updateQueries: string[] = []; for (let i = 0; i < finalPoolDataUpdate.length; ++i) { updateQueries.push(` UPDATE pools @@ -141,4 +141,4 @@ class PoolsParser { } -export default new PoolsParser(); \ No newline at end of file +export default new PoolsParser(); From a9eb0ab4bb6f46b0f2386db702431d92d85283a8 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 20 Jan 2022 16:56:25 +0900 Subject: [PATCH 05/63] Fix add 'Unknown' pool logic --- backend/src/api/pools-parser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index da048f2d3..9bfcd3366 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -93,7 +93,7 @@ class PoolsParser { } // Manually add the 'unknown pool' - if (existingPools.find((pool) => pool.name === 'Unknown') !== undefined) { + if (existingPools.find((pool) => pool.name === 'Unknown') === undefined) { finalPoolDataAdd.push({ 'name': 'Unknown', 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', From 1abfa4a82e5141425a99e017b9a543c94918c369 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 20 Jan 2022 22:59:10 +0900 Subject: [PATCH 06/63] Add pools.json file in default config.ts - Handle file exception - Only import pools for MAINNET --- backend/src/api/pools-parser.ts | 82 ++++++++++++++++++++------------- backend/src/config.ts | 4 +- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 9bfcd3366..bb7779089 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -1,6 +1,7 @@ -import {readFileSync} from 'fs'; +import { readFileSync } from 'fs'; import { DB } from '../database'; import logger from '../logger'; +import config from '../config'; interface Pool { name: string; @@ -14,20 +15,26 @@ class PoolsParser { * Parse the pools.json file, consolidate the data and dump it into the database */ public async migratePoolsJson() { - const connection = await DB.pool.getConnection(); - logger.info('Importing pools.json to the database'); + if (config.MEMPOOL.NETWORK !== 'mainnet') { + return; + } - // Get existing pools from the db - const [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); + logger.debug('Importing pools.json to the database, open ./pools.json'); - logger.info('Open ./pools.json'); - const fileContent: string = readFileSync('./pools.json', 'utf8'); - const poolsJson: object = JSON.parse(fileContent); + let poolsJson: object = {}; + try { + const fileContent: string = readFileSync('./pools.json', 'utf8'); + poolsJson = JSON.parse(fileContent); + } catch (e) { + logger.err('Unable to open ./pools.json, does the file exist?'); + await this.insertUnknownPool(); + return; + } // First we save every entries without paying attention to pool duplication const poolsDuplicated: Pool[] = []; - logger.info('Parse coinbase_tags'); + logger.debug('Parse coinbase_tags'); const coinbaseTags = Object.entries(poolsJson['coinbase_tags']); for (let i = 0; i < coinbaseTags.length; ++i) { poolsDuplicated.push({ @@ -37,7 +44,7 @@ class PoolsParser { 'addresses': [], }); } - logger.info('Parse payout_addresses'); + logger.debug('Parse payout_addresses'); const addressesTags = Object.entries(poolsJson['payout_addresses']); for (let i = 0; i < addressesTags.length; ++i) { poolsDuplicated.push({ @@ -49,14 +56,18 @@ class PoolsParser { } // Then, we find unique mining pool names - logger.info('Identify unique mining pools'); + logger.debug('Identify unique mining pools'); const poolNames: string[] = []; for (let i = 0; i < poolsDuplicated.length; ++i) { if (poolNames.indexOf(poolsDuplicated[i].name) === -1) { poolNames.push(poolsDuplicated[i].name); } } - logger.info(`Found ${poolNames.length} unique mining pools`); + logger.debug(`Found ${poolNames.length} unique mining pools`); + + // Get existing pools from the db + const connection = await DB.pool.getConnection(); + const [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); // Finally, we generate the final consolidated pools data const finalPoolDataAdd: Pool[] = []; @@ -92,23 +103,13 @@ class PoolsParser { } } - // Manually add the 'unknown pool' - if (existingPools.find((pool) => pool.name === 'Unknown') === undefined) { - finalPoolDataAdd.push({ - 'name': 'Unknown', - 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', - regexes: [], - addresses: [], - }); - } - - logger.info(`Update pools table now`); + logger.debug(`Update pools table now`); // Add new mining pools into the database let queryAdd: string = 'INSERT INTO pools(name, link, regexes, addresses) VALUES '; for (let i = 0; i < finalPoolDataAdd.length; ++i) { queryAdd += `('${finalPoolDataAdd[i].name}', '${finalPoolDataAdd[i].link}', - '${JSON.stringify(finalPoolDataAdd[i].regexes)}', '${JSON.stringify(finalPoolDataAdd[i].addresses)}'),`; + '${JSON.stringify(finalPoolDataAdd[i].regexes)}', '${JSON.stringify(finalPoolDataAdd[i].addresses)}'),`; } queryAdd = queryAdd.slice(0, -1) + ';'; @@ -116,11 +117,11 @@ class PoolsParser { const updateQueries: string[] = []; for (let i = 0; i < finalPoolDataUpdate.length; ++i) { updateQueries.push(` - UPDATE pools - SET name='${finalPoolDataUpdate[i].name}', link='${finalPoolDataUpdate[i].link}', - regexes='${JSON.stringify(finalPoolDataUpdate[i].regexes)}', addresses='${JSON.stringify(finalPoolDataUpdate[i].addresses)}' - WHERE name='${finalPoolDataUpdate[i].name}' - ;`); + UPDATE pools + SET name='${finalPoolDataUpdate[i].name}', link='${finalPoolDataUpdate[i].link}', + regexes='${JSON.stringify(finalPoolDataUpdate[i].regexes)}', addresses='${JSON.stringify(finalPoolDataUpdate[i].addresses)}' + WHERE name='${finalPoolDataUpdate[i].name}' + ;`); } try { @@ -130,15 +131,34 @@ class PoolsParser { updateQueries.forEach(async query => { await connection.query({ sql: query, timeout: 120000 }); }); + await this.insertUnknownPool(); connection.release(); - logger.info('Import completed'); + logger.info('Mining pools.json import completed'); } catch (e) { connection.release(); - logger.info(`Unable to import pools in the database!`); + logger.err(`Unable to import pools in the database!`); throw e; } } + /** + * Manually add the 'unknown pool' + */ + private async insertUnknownPool() { + const connection = await DB.pool.getConnection(); + try { + const [rows]: any[] = await connection.query({ sql: 'SELECT name from pools where name="Unknown"', timeout: 120000 }); + if (rows.length === 0) { + logger.debug('Manually inserting "Unknown" mining pool into the databse'); + await connection.query({ + sql: `INSERT INTO pools(name, link, regexes, addresses) + VALUES("Unknown", "https://learnmeabitcoin.com/technical/coinbase-transaction", "[]", "[]"); + `}); + } + } catch (e) { + logger.err('Unable to insert "Unknown" mining pool'); + } + } } export default new PoolsParser(); diff --git a/backend/src/config.ts b/backend/src/config.ts index 4c2888834..3cc928327 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -79,7 +79,9 @@ const defaults: IConfig = { 'MEMPOOL_BLOCKS_AMOUNT': 8, 'PRICE_FEED_UPDATE_INTERVAL': 3600, 'USE_SECOND_NODE_FOR_MINFEE': false, - 'EXTERNAL_ASSETS': [], + 'EXTERNAL_ASSETS': [ + 'https://mempool.space/resources/pools.json' + ] }, 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', From 0b8244d19a4840f6991a05aa407473542df78d0f Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 20 Jan 2022 23:07:20 +0900 Subject: [PATCH 07/63] Make sure to release all db connections --- backend/src/api/pools-parser.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index bb7779089..2b0901551 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -67,7 +67,14 @@ class PoolsParser { // Get existing pools from the db const connection = await DB.pool.getConnection(); - const [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); + let existingPools: any[] = []; + try { + existingPools = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); + } catch (e) { + logger.err('Unable to get existing pools from the database, skipping pools.json import'); + connection.release(); + return; + } // Finally, we generate the final consolidated pools data const finalPoolDataAdd: Pool[] = []; @@ -117,11 +124,11 @@ class PoolsParser { const updateQueries: string[] = []; for (let i = 0; i < finalPoolDataUpdate.length; ++i) { updateQueries.push(` - UPDATE pools - SET name='${finalPoolDataUpdate[i].name}', link='${finalPoolDataUpdate[i].link}', - regexes='${JSON.stringify(finalPoolDataUpdate[i].regexes)}', addresses='${JSON.stringify(finalPoolDataUpdate[i].addresses)}' - WHERE name='${finalPoolDataUpdate[i].name}' - ;`); + UPDATE pools + SET name='${finalPoolDataUpdate[i].name}', link='${finalPoolDataUpdate[i].link}', + regexes='${JSON.stringify(finalPoolDataUpdate[i].regexes)}', addresses='${JSON.stringify(finalPoolDataUpdate[i].addresses)}' + WHERE name='${finalPoolDataUpdate[i].name}' + ;`); } try { @@ -158,6 +165,8 @@ class PoolsParser { } catch (e) { logger.err('Unable to insert "Unknown" mining pool'); } + + connection.release(); } } From 0df75cb3a9d21bbad3042c601e6b0e087d66dc00 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 20 Jan 2022 23:31:32 +0900 Subject: [PATCH 08/63] Fix typescript miss use --- backend/src/api/pools-parser.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 2b0901551..e3f5f0b89 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -67,9 +67,9 @@ class PoolsParser { // Get existing pools from the db const connection = await DB.pool.getConnection(); - let existingPools: any[] = []; + let existingPools; try { - existingPools = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); + [existingPools] = await connection.query({ sql: 'SELECT * FROM pools;', timeout: 120000 }); } catch (e) { logger.err('Unable to get existing pools from the database, skipping pools.json import'); connection.release(); From e87fb403c632f521dd8ce3ccee402c4ad927b2f8 Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 20 Jan 2022 19:47:18 +0400 Subject: [PATCH 09/63] Display Liquid asset icons --- .../src/app/components/asset/asset.component.html | 14 +++++++------- .../src/app/components/asset/asset.component.scss | 14 ++++++++++++++ .../src/app/components/asset/asset.component.ts | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index c79e260b6..dba70dc5d 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -35,13 +35,6 @@ Issuance TX {{ asset.issuance_txin.txid | shortenString : 13 }} - - - -
-
- - @@ -69,6 +62,13 @@
Pegged in {{ formatAmount(asset.chain_stats.peg_in_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
+
+
+ + + + +
diff --git a/frontend/src/app/components/asset/asset.component.scss b/frontend/src/app/components/asset/asset.component.scss index 270ad97e3..3fe93c9d2 100644 --- a/frontend/src/app/components/asset/asset.component.scss +++ b/frontend/src/app/components/asset/asset.component.scss @@ -50,3 +50,17 @@ h1 { } } +.assetIcon { + max-height: 150px; + margin: 25px; + @media (min-width: 768px) { + max-height: 300px; + margin: 0; + } +} + +.icon-holder { + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/frontend/src/app/components/asset/asset.component.ts b/frontend/src/app/components/asset/asset.component.ts index 74b074d97..ecb216052 100644 --- a/frontend/src/app/components/asset/asset.component.ts +++ b/frontend/src/app/components/asset/asset.component.ts @@ -32,6 +32,7 @@ export class AssetComponent implements OnInit, OnDestroy { isNativeAsset = false; error: any; mainSubscription: Subscription; + imageError = false; totalConfirmedTxCount = 0; loadedConfirmedTxCount = 0; From da0eec4127e609d8a17ae251b45f4b6975377656 Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 20 Jan 2022 22:56:49 +0400 Subject: [PATCH 10/63] Liquid asset loading fixes --- frontend/src/app/assets/assets.component.html | 2 +- .../app/components/asset/asset.component.html | 53 +++++++++++-------- .../app/components/asset/asset.component.scss | 15 ++++-- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/frontend/src/app/assets/assets.component.html b/frontend/src/app/assets/assets.component.html index 5d5118af0..c8962cd15 100644 --- a/frontend/src/app/assets/assets.component.html +++ b/frontend/src/app/assets/assets.component.html @@ -43,7 +43,7 @@ Name Ticker - Issuer domain + Issuer domain Asset ID diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index dba70dc5d..c0a2bfbf5 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -66,7 +66,7 @@
- +
@@ -109,28 +109,39 @@ - -
- - - - - - - - - - - - -
-
-
-
- - +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
diff --git a/frontend/src/app/components/asset/asset.component.scss b/frontend/src/app/components/asset/asset.component.scss index 3fe93c9d2..bb2b7f783 100644 --- a/frontend/src/app/components/asset/asset.component.scss +++ b/frontend/src/app/components/asset/asset.component.scss @@ -51,10 +51,10 @@ h1 { } .assetIcon { - max-height: 150px; + height: 150px; margin: 25px; @media (min-width: 768px) { - max-height: 300px; + height: 250px; margin: 0; } } @@ -63,4 +63,13 @@ h1 { display: flex; justify-content: center; align-items: center; -} \ No newline at end of file +} + +.defaultIcon { + margin: 25px; + height: 150px; +} + +.defaultIcon.skeleton { + opacity: 0.5; +} From ecc2bb56845e9f7007d32dd5c2b8bc5519d1855f Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 11:27:50 -0800 Subject: [PATCH 11/63] Fix Liquid proxy settings --- frontend/proxy.conf.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/proxy.conf.js b/frontend/proxy.conf.js index faae04499..4a0489c77 100644 --- a/frontend/proxy.conf.js +++ b/frontend/proxy.conf.js @@ -61,10 +61,7 @@ PROXY_CONFIG = [ }, { context: ['/api/liquidtestnet**', '/liquidtestnet/api/**'], - target: "https://liquid.network/testnet", - pathRewrite: { - "^/api/liquidtestnet/": "/liquidtestnet/api" - }, + target: "https://liquid.network", ws: true, secure: false, changeOrigin: true @@ -73,7 +70,9 @@ PROXY_CONFIG = [ if (configContent && configContent.BASE_MODULE == "liquid") { PROXY_CONFIG.push({ - context: ['/resources/pools.json', '/resources/assets.json', '/resources/assets.minimal.json'], + context: ['/resources/pools.json', + '/resources/assets.json', '/resources/assets.minimal.json', + '/resources/assets-testnet.json', '/resources/assets-testnet.minimal.json'], target: "https://liquid.network", secure: false, changeOrigin: true, From 547469dab559ffd63577928d1b7b49f330b5aed5 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 21 Jan 2022 00:16:18 +0400 Subject: [PATCH 12/63] Asset name overflow fix --- frontend/src/app/components/asset/asset.component.html | 2 +- frontend/src/app/components/asset/asset.component.scss | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index c0a2bfbf5..9723a45e5 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -21,7 +21,7 @@ Name - {{ assetContract[2] }} ({{ assetContract[1] }}) + {{ assetContract[2] }} ({{ assetContract[1] }}) Precision diff --git a/frontend/src/app/components/asset/asset.component.scss b/frontend/src/app/components/asset/asset.component.scss index bb2b7f783..45e68042d 100644 --- a/frontend/src/app/components/asset/asset.component.scss +++ b/frontend/src/app/components/asset/asset.component.scss @@ -73,3 +73,8 @@ h1 { .defaultIcon.skeleton { opacity: 0.5; } + +.assetName { + word-break: break-word; + white-space: normal; +} From be77e3ff78764445d9a59e52ae81a9f49e8c0f96 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 21 Jan 2022 01:32:19 +0400 Subject: [PATCH 13/63] Fixing liqud asset precision fixes #1166 --- .../transactions-list/transactions-list.component.html | 2 +- .../transactions-list/transactions-list.component.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index 36aed7fe6..680b6be53 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -270,7 +270,7 @@ - {{ item.value / 100000000 | number: '1.0-' + assetsMinimal[item.asset][3] }} {{ assetsMinimal[item.asset][1] }} + {{ item.value / pow(10, assetsMinimal[item.asset][3]) | number: '1.' + assetsMinimal[item.asset][3] + '-' + assetsMinimal[item.asset][3] }} {{ assetsMinimal[item.asset][1] }}
{{ assetsMinimal[item.asset][0] }}
diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.ts b/frontend/src/app/components/transactions-list/transactions-list.component.ts index ecddf4436..e1fb7d2e6 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.ts +++ b/frontend/src/app/components/transactions-list/transactions-list.component.ts @@ -119,6 +119,10 @@ export class TransactionsListComponent implements OnInit, OnChanges { return '0x' + (str.length % 2 ? '0' : '') + str; } + pow(base: number, exponent: number): number { + return Math.pow(base, exponent); + } + toggleDetails() { this.displayDetails = !this.displayDetails; this.ref.markForCheck(); From b03c398859e0c4bf3994549f32ae472191fa1cdf Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 21:27:52 -0800 Subject: [PATCH 14/63] Update Cypress to v9.3.1 --- frontend/package-lock.json | 60 ++++++++++++++++++++------------------ frontend/package.json | 2 +- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index befb9d3ac..9768eb6df 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -70,7 +70,7 @@ }, "optionalDependencies": { "@cypress/schematic": "^1.3.0", - "cypress": "^9.1.1", + "cypress": "^9.3.1", "cypress-fail-on-console-error": "^2.1.3", "cypress-wait-until": "^1.7.1", "mock-socket": "^9.0.3", @@ -3801,9 +3801,9 @@ } }, "node_modules/@types/sinonjs__fake-timers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz", - "integrity": "sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", "optional": true }, "node_modules/@types/sizzle": { @@ -5746,17 +5746,18 @@ } }, "node_modules/cli-table3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", - "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", "optional": true, "dependencies": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", "string-width": "^4.2.0" }, "engines": { "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "1.4.0" } }, "node_modules/cli-truncate": { @@ -6786,25 +6787,26 @@ "devOptional": true }, "node_modules/cypress": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.1.1.tgz", - "integrity": "sha512-yWcYD8SEQ8F3okFbRPqSDj5V0xhrZBT5QRIH+P1J2vYvtEmZ4KGciHE7LCcZZLILOrs7pg4WNCqkj/XRvReQlQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.3.1.tgz", + "integrity": "sha512-BODdPesxX6bkVUnH8BVsV8I/jn57zQtO1FEOUTiuG2us3kslW7g0tcuwiny7CKCmJUZz8S/D587ppC+s58a+5Q==", "hasInstallScript": true, "optional": true, "dependencies": { "@cypress/request": "^2.88.10", "@cypress/xvfb": "^1.2.4", "@types/node": "^14.14.31", - "@types/sinonjs__fake-timers": "^6.0.2", + "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", "blob-util": "^2.0.2", - "bluebird": "3.7.2", + "bluebird": "^3.7.2", + "buffer": "^5.6.0", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.0", + "cli-table3": "~0.6.1", "commander": "^5.1.0", "common-tags": "^1.8.0", "dayjs": "^1.10.4", @@ -20861,9 +20863,9 @@ } }, "@types/sinonjs__fake-timers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz", - "integrity": "sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", "optional": true }, "@types/sizzle": { @@ -22536,13 +22538,12 @@ "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==" }, "cli-table3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz", - "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", "optional": true, "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", + "colors": "1.4.0", "string-width": "^4.2.0" } }, @@ -23373,24 +23374,25 @@ "devOptional": true }, "cypress": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.1.1.tgz", - "integrity": "sha512-yWcYD8SEQ8F3okFbRPqSDj5V0xhrZBT5QRIH+P1J2vYvtEmZ4KGciHE7LCcZZLILOrs7pg4WNCqkj/XRvReQlQ==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.3.1.tgz", + "integrity": "sha512-BODdPesxX6bkVUnH8BVsV8I/jn57zQtO1FEOUTiuG2us3kslW7g0tcuwiny7CKCmJUZz8S/D587ppC+s58a+5Q==", "optional": true, "requires": { "@cypress/request": "^2.88.10", "@cypress/xvfb": "^1.2.4", "@types/node": "^14.14.31", - "@types/sinonjs__fake-timers": "^6.0.2", + "@types/sinonjs__fake-timers": "8.1.1", "@types/sizzle": "^2.3.2", "arch": "^2.2.0", "blob-util": "^2.0.2", - "bluebird": "3.7.2", + "bluebird": "^3.7.2", + "buffer": "^5.6.0", "cachedir": "^2.3.0", "chalk": "^4.1.0", "check-more-types": "^2.24.0", "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.0", + "cli-table3": "~0.6.1", "commander": "^5.1.0", "common-tags": "^1.8.0", "dayjs": "^1.10.4", diff --git a/frontend/package.json b/frontend/package.json index 44ca13e90..d23e7b3b7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -117,7 +117,7 @@ }, "optionalDependencies": { "@cypress/schematic": "^1.3.0", - "cypress": "^9.1.1", + "cypress": "^9.3.1", "cypress-fail-on-console-error": "^2.1.3", "cypress-wait-until": "^1.7.1", "mock-socket": "^9.0.3", From 13d82035de963c57ae66534a668c659f660488fd Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 21:29:45 -0800 Subject: [PATCH 15/63] Update config script defaults --- frontend/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 44ca13e90..3debb384a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -42,9 +42,9 @@ "lint": "ng lint", "e2e": "npm run generate-config && ng e2e", "e2e:ci": "npm run cypress:run:ci", - "config:defaults:mempool": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=mempool && npm run generate-config", - "config:defaults:liquid": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=liquid && npm run generate-config", - "config:defaults:bisq": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=bisq && npm run generate-config", + "config:defaults:mempool": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true LIQUID_TESTNET_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=mempool BLOCK_WEIGHT_UNITS=4000000 && npm run generate-config", + "config:defaults:liquid": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true LIQUID_TESTNET_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=liquid BLOCK_WEIGHT_UNITS=300000 && npm run generate-config", + "config:defaults:bisq": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=bisq BLOCK_WEIGHT_UNITS=4000000 && npm run generate-config", "dev:ssr": "npm run generate-config && ng run mempool:serve-ssr", "serve:ssr": "node server.run.js", "build:ssr": "npm run build && ng run mempool:server:production && ./node_modules/typescript/bin/tsc server.run.ts", From 92af56359bc807952e3208a5c0cf8f99696e9b84 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 21:30:03 -0800 Subject: [PATCH 16/63] Add Liquid Testnet tests --- .../liquidtestnet/liquidtestnet.spec.ts | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts diff --git a/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts b/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts new file mode 100644 index 000000000..bef477d4b --- /dev/null +++ b/frontend/cypress/integration/liquidtestnet/liquidtestnet.spec.ts @@ -0,0 +1,179 @@ +describe('Liquid Testnet', () => { + const baseModule = Cypress.env("BASE_MODULE"); + const basePath = '/testnet'; + + beforeEach(() => { + cy.intercept('/liquidtestnet/api/block/**').as('block'); + cy.intercept('/liquidtestnet/api/blocks/').as('blocks'); + cy.intercept('/liquidtestnet/api/tx/**/outspends').as('outspends'); + cy.intercept('/liquidtestnet/api/block/**/txs/**').as('block-txs'); + cy.intercept('/resources/pools.json').as('pools'); + + Cypress.Commands.add('waitForBlockData', () => { + cy.wait('@socket'); + cy.wait('@block'); + cy.wait('@outspends'); + }); + }); + + if (baseModule === 'liquid') { + + it('check first mempool block after skeleton loads', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').should('exist'); + }); + + it('loads the dashboard', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + }); + + it('loads the blocks page', () => { + cy.visit(`${basePath}/blocks`); + cy.waitForSkeletonGone(); + }); + + it('loads a specific block page', () => { + cy.visit(`${basePath}/block/7e1369a23a5ab861e7bdede2aadcccae4ea873ffd9caf11c7c5541eb5bcdff54`); + cy.waitForSkeletonGone(); + }); + + it('loads the graphs page', () => { + cy.visit(`${basePath}/graphs`); + cy.waitForSkeletonGone(); + }); + + it('loads the tv page - desktop', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.get('li:nth-of-type(3) > a').click().then(() => { + cy.wait(1000); + }); + }); + + it('loads the graphs page - mobile', () => { + cy.visit(`${basePath}`) + cy.waitForSkeletonGone(); + cy.get('li:nth-of-type(3) > a').click().then(() => { + cy.viewport('iphone-6'); + cy.wait(1000); + cy.get('.tv-only').should('not.exist'); + }); + }); + + it.skip('renders unconfidential addresses correctly on mobile', () => { + cy.viewport('iphone-6'); + cy.visit(`${basePath}/address/__TODO__`); + 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('assets', () => { + it('shows the assets screen', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('table tr').should('have.length.at.least', 5); + }); + + it('allows searching assets', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.container-xl input').click().type('Liquid Bitcoin').then(() => { + cy.get('table tr').should('have.length', 1); + }); + }); + + it('shows a specific asset ID', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.container-xl input').click().type('Liquid CAD').then(() => { + cy.get('table tr td:nth-of-type(1) a').click(); + }); + }); + }); + + describe('unblinded TX', () => { + it('should not show an unblinding error message for regular txs', () => { + cy.visit(`${basePath}/tx/82a479043ec3841e0d3f829afc8df4f0e2bbd675a13f013ea611b2fde0027d45`); + cy.waitForSkeletonGone(); + cy.get('.error-unblinded' ).should('not.exist'); + }); + + it('show unblinded TX', () => { + cy.visit(`${basePath}/tx/c3d908ab77891e4c569b0df71aae90f4720b157019ebb20db176f4f9c4d626b8#blinded=100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,df290ead654d7d110ebc5aaf0bcf11d5b5d360431a467f1cde0a856fde986893,33cb3a2fd2e76643843691cf44a78c5cd28ec652a414da752160ad63fbd37bc9,49741,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,edb0713bcbfcb3daabf601cb50978439667d208e15fed8a5ebbfea5696cda1d5,4de70115501e8c7d6bd763e229bf42781edeacf6e75e1d7bdfa4c63104bc508a`); + cy.waitForSkeletonGone(); + cy.get('#table-tx-vin tr:nth-child(1) .amount').should('contain.text', '0.00100000 tL-BTC'); + cy.get('#table-tx-vin tr').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00050000 tL-BTC'); + cy.get('#table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0.00049741 tL-BTC'); + cy.get('#table-tx-vout tr').should('have.class', 'assetBox'); + }); + + it('show empty unblinded TX', () => { + cy.visit(`${basePath}/tx/c3d908ab77891e4c569b0df71aae90f4720b157019ebb20db176f4f9c4d626b8#blinded=`); + cy.waitForSkeletonGone(); + cy.get('#table-tx-vin tr:nth-child(1)').should('have.class', ''); + cy.get('#table-tx-vin tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('#table-tx-vout tr:nth-child(1)').should('have.class', ''); + cy.get('#table-tx-vout tr:nth-child(2)').should('have.class', ''); + cy.get('#table-tx-vout tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('#table-tx-vout tr:nth-child(2) .amount').should('contain.text', 'Confidential'); + }); + + it('show invalid unblinded TX hex', () => { + cy.visit(`${basePath}/tx/2477f220eef1d03f8ffa4a2861c275d155c3562adf0d79523aeeb0c59ee611ba#blinded=5000`); + cy.waitForSkeletonGone(); + cy.get('#table-tx-vin tr').should('have.class', ''); + cy.get('#table-tx-vout tr').should('have.class', ''); + cy.get('.error-unblinded' ).contains('Error: Invalid blinding data (invalid hex)'); + }); + + it('show first unblinded vout', () => { + cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); + cy.waitForSkeletonGone(); + cy.get('#table-tx-vout tr:nth-child(1)').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00099729 tL-BTC'); + }); + + it('show second unblinded vout (asset)', () => { + cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); + cy.get('#table-tx-vout tr:nth-child(2)').should('have.class', 'assetBox'); + //TODO Update after the precision bug fix is merged + cy.get('#table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0 TEST'); + }); + + it('should link to the asset page from the unblinded tx', () => { + cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); + cy.get('#table-tx-vout tr:nth-child(2) .amount a').click().then(() => { + cy.waitForSkeletonGone(); + cy.url().should('contain', '/asset/38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5'); + }); + }); + + it('show invalid error unblinded TX', () => { + cy.visit(`${basePath}/tx/c3d908ab77891e4c569b0df71aae90f4720b157019ebb20db176f4f9c4d626b8#blinded=100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,df290ead654d7d110ebc5aaf0bcf11d5b5d360431a467f1cde0a856fde986893,33cb3a2fd2e76643843691cf44a78c5cd28ec652a414da752160ad63fbd37bc9,49741,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,edb0713bcbfcb3daabf601cb50978439667d208e15fed8a5ebbfea5696cda1d5,4de70115501e8c7d6bd763e229bf42781edeacf6e75e1d7bdfa4c63104bc508c`); + cy.waitForSkeletonGone(); + cy.get('#table-tx-vin tr').should('have.class', 'assetBox'); + cy.get('.error-unblinded' ).contains('Error: Invalid blinding data.'); + }); + + it('shows asset peg in/out and burn transactions', () => { + cy.visit(`${basePath}/asset/ac3e0ff248c5051ffd61e00155b7122e5ebc04fd397a0ecbdd4f4e4a56232926`); + cy.waitForSkeletonGone(); + cy.get('#table-tx-vout tr').not('.assetBox'); + cy.get('#table-tx-vin tr').not('.assetBox'); + }); + + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); From 8935074a2749650b952b2bb1374d2b66bd60f3f9 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 21:30:22 -0800 Subject: [PATCH 17/63] Update Liquid tests --- .../cypress/integration/liquid/liquid.spec.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/frontend/cypress/integration/liquid/liquid.spec.ts b/frontend/cypress/integration/liquid/liquid.spec.ts index 5661340f4..b705655d3 100644 --- a/frontend/cypress/integration/liquid/liquid.spec.ts +++ b/frontend/cypress/integration/liquid/liquid.spec.ts @@ -146,15 +146,22 @@ describe('Liquid', () => { it('show unblinded TX', () => { cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc,2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3a`); cy.waitForSkeletonGone(); + cy.get('#table-tx-vin tr:nth-child(1) .amount').should('contain.text', '0.02465000 L-BTC'); cy.get('#table-tx-vin tr').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00100000 L-BTC'); + cy.get('#table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0.02364760 L-BTC'); cy.get('#table-tx-vout tr').should('have.class', 'assetBox'); }); it('show empty unblinded TX', () => { cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=`); cy.waitForSkeletonGone(); - cy.get('#table-tx-vin tr').should('have.class', ''); - cy.get('#table-tx-vout tr').should('have.class', ''); + cy.get('#table-tx-vin tr:nth-child(1)').should('have.class', ''); + cy.get('#table-tx-vin tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('#table-tx-vout tr:nth-child(1)').should('have.class', ''); + cy.get('#table-tx-vout tr:nth-child(2)').should('have.class', ''); + cy.get('#table-tx-vout tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('#table-tx-vout tr:nth-child(2) .amount').should('contain.text', 'Confidential'); }); it('show invalid unblinded TX hex', () => { @@ -168,12 +175,14 @@ describe('Liquid', () => { it('show first unblinded vout', () => { cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc`); cy.waitForSkeletonGone(); - cy.get('#table-tx-vout tr:first-child()').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(1)').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00100000 L-BTC'); }); it('show second unblinded vout', () => { cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3a`); - cy.get('#table-tx-vout tr').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(2').should('have.class', 'assetBox'); + cy.get('#table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0.02364760 L-BTC'); }); it('show invalid error unblinded TX', () => { From 019c732272c97cc9d75aef06f0b7e13590be1885 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 21:31:14 -0800 Subject: [PATCH 18/63] Add an amount class vins and vouts to improve testing --- .../transactions-list/transactions-list.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index 36aed7fe6..6eb262377 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -71,7 +71,7 @@ - +
@@ -170,7 +170,7 @@ - +
From 8e37b2a78048f9d4c4d6b1cd3e39ba8a37af2fd6 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Thu, 20 Jan 2022 21:43:13 -0800 Subject: [PATCH 19/63] Update Cypress GHA spec list --- .github/workflows/cypress.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index 1b565e71a..832efcbbf 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -31,6 +31,10 @@ jobs: wait-on-timeout: 120 record: true parallel: true + spec: | + cypress/integration/mainnet/*.spec.ts + cypress/integration/signet/*.spec.ts + cypress/integration/testnet/*.spec.ts group: Tests on ${{ matrix.browser }} (Mempool) browser: ${{ matrix.browser }} ci-build-id: '${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}' @@ -50,7 +54,9 @@ jobs: wait-on-timeout: 120 record: true parallel: true - spec: cypress/integration/liquid/liquid.spec.ts + spec: | + cypress/integration/liquid/liquid.spec.ts + cypress/integration/liquidtestnet/liquidtestnet.spec.ts group: Tests on ${{ matrix.browser }} (Liquid) browser: ${{ matrix.browser }} ci-build-id: '${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}' From 824fc5c22c25cadd21bb182225747813a1b1ff76 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Fri, 21 Jan 2022 23:12:18 -0800 Subject: [PATCH 20/63] Fix broken link on the Bisq transaction page --- .../app/bisq/bisq-transaction/bisq-transaction.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html index 57862fed6..2b3964caa 100644 --- a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html +++ b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html @@ -7,7 +7,7 @@
- + {{ bisqTx.id | shortenString : 24 }} {{ bisqTx.id }} From 505b8e86cf47657406cfeb3e8b34ddeafcc5c9a0 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn Date: Sat, 22 Jan 2022 14:21:46 -0800 Subject: [PATCH 21/63] Add ids to nav bar items, liquid and bisq components --- .../bisq-transactions.component.html | 4 ++-- .../bisq-master-page.component.html | 12 +++++------ .../liquid-master-page.component.html | 12 +++++------ .../master-page/master-page.component.html | 20 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html index f85c29a9b..d1064972e 100644 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html +++ b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html @@ -1,7 +1,7 @@

BSQ Transactions

-
+
@@ -39,7 +39,7 @@ {{ tx.blockHeight }} - + diff --git a/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html b/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html index d77f96423..cacd38f39 100644 --- a/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html +++ b/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html @@ -27,22 +27,22 @@