From de929b4f7e790b635d67815d0ca895c387d36c08 Mon Sep 17 00:00:00 2001 From: bludnic Date: Fri, 9 Feb 2024 00:28:49 +0000 Subject: [PATCH 001/218] feat: handle login errors --- src/components/LoginForm.vue | 10 +++++++++- src/components/SendFundsForm.vue | 2 +- src/lib/nodes/abstract.client.ts | 2 +- src/lib/nodes/adm/AdmClient.ts | 8 +------- src/lib/nodes/utils/errors.ts | 14 ++++++++++++-- src/locales/en.json | 5 ++++- src/locales/ru.json | 5 ++++- src/locales/zh.json | 5 ++++- 8 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/components/LoginForm.vue b/src/components/LoginForm.vue index 90ed4842d..1d448ac86 100644 --- a/src/components/LoginForm.vue +++ b/src/components/LoginForm.vue @@ -55,6 +55,8 @@ import { validateMnemonic } from 'bip39' import { computed, ref, defineComponent } from 'vue' import { useStore } from 'vuex' +import { isAxiosError } from 'axios' +import { isAllNodesOfflineError } from '@/lib/nodes/utils/errors' export default defineComponent({ props: { @@ -98,8 +100,14 @@ export default defineComponent({ emit('login') }) .catch((err) => { + if (isAxiosError(err)) { + emit('error', 'login.invalid_passphrase') + } else if (isAllNodesOfflineError(err)) { + emit('error', 'errors.all_nodes_offline') + } else { + emit('error', 'errors.something_went_wrong') + } console.log(err) - emit('error', 'login.invalid_passphrase') }) .finally(() => { antiFreeze() diff --git a/src/components/SendFundsForm.vue b/src/components/SendFundsForm.vue index 236817ce0..cfb8cece4 100644 --- a/src/components/SendFundsForm.vue +++ b/src/components/SendFundsForm.vue @@ -746,7 +746,7 @@ export default { } else if (/Invalid JSON RPC Response/i.test(message)) { message = this.$t('transfer.error_unknown') } else if (error instanceof AllNodesOfflineError) { - message = this.$t('transfer.error_all_nodes_offline', { + message = this.$t('errors.all_nodes_offline', { crypto: error.nodeLabel.toUpperCase() }) } else if (error instanceof PendingTransactionError) { diff --git a/src/lib/nodes/abstract.client.ts b/src/lib/nodes/abstract.client.ts index 62ff6f81c..b376b9687 100644 --- a/src/lib/nodes/abstract.client.ts +++ b/src/lib/nodes/abstract.client.ts @@ -129,7 +129,7 @@ export abstract class Client { // All nodes seem to be offline: let's refresh the statuses this.checkHealth() // But there's nothing we can do right now - throw new Error('No online nodes at the moment') + throw new AllNodesOfflineError(this.type) } return node diff --git a/src/lib/nodes/adm/AdmClient.ts b/src/lib/nodes/adm/AdmClient.ts index c68afabb6..63d258e1a 100644 --- a/src/lib/nodes/adm/AdmClient.ts +++ b/src/lib/nodes/adm/AdmClient.ts @@ -41,13 +41,7 @@ export class AdmClient extends Client { * @param {RequestConfig} config request config */ async request

(config: RequestConfig

): Promise { - const node = this.useFastest ? this.getFastestNode() : this.getRandomNode() - if (!node) { - // All nodes seem to be offline: let's refresh the statuses - this.checkHealth() - // But there's nothing we can do right now - return Promise.reject(new Error('No online nodes at the moment')) - } + const node = this.getNode() return node.request(config).catch((error) => { if (isNodeOfflineError(error)) { diff --git a/src/lib/nodes/utils/errors.ts b/src/lib/nodes/utils/errors.ts index 52eebfb39..3190f1758 100644 --- a/src/lib/nodes/utils/errors.ts +++ b/src/lib/nodes/utils/errors.ts @@ -1,10 +1,15 @@ import { NodeType } from '@/lib/nodes/types' +const CODES = { + NODE_OFFLINE: 'NODE_OFFLINE', + ALL_NODES_OFFLINE: 'ALL_NODES_OFFLINE' +} as const + /** * Custom error to indicate that the endpoint is not available */ export class NodeOfflineError extends Error { - code = 'NODE_OFFLINE' + code = CODES.NODE_OFFLINE constructor() { super('Node is offline') @@ -16,7 +21,7 @@ export class NodeOfflineError extends Error { } export function isNodeOfflineError(error: Error): error is NodeOfflineError { - return (error as NodeOfflineError).code === 'NODE_OFFLINE' + return (error as NodeOfflineError).code === CODES.NODE_OFFLINE } /** @@ -29,6 +34,7 @@ export class TransactionNotFound extends Error { } export class AllNodesOfflineError extends Error { + code = CODES.ALL_NODES_OFFLINE nodeLabel: NodeType // to distinct eth-node from eth-indexer it may be better to use TNodeLabel constructor(label: NodeType) { @@ -37,3 +43,7 @@ export class AllNodesOfflineError extends Error { this.nodeLabel = label } } + +export function isAllNodesOfflineError(error: Error): error is AllNodesOfflineError { + return (error as AllNodesOfflineError).code === CODES.ALL_NODES_OFFLINE +} diff --git a/src/locales/en.json b/src/locales/en.json index 8a615e01b..71444466c 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -86,6 +86,10 @@ "online": "Online—Connection is set" }, "error": "Error", + "errors": { + "something_went_wrong": "Something went wrong. Check the console for details", + "all_nodes_offline": "All {crypto} nodes are offline. Try again later" + }, "home": { "balance": "Balance", "buy_tokens_anonymously": "Anonymously on website", @@ -312,7 +316,6 @@ "error_chat_fee": "To send {crypto} via chat, you need 0.001 ADM", "error_dust_amount": "Dust amount—Send more tokens", "recipient_minimum_balance": "Recipient must have at least 0.05 LSK—Send more tokens", - "error_all_nodes_offline": "All {crypto} nodes are offline. Try again later", "error_precision": "Too high precision—Set less decimal places", "error_erc20_fee": "You need a {fee} to pay a transfer fee", "error_field_is_required": "Field is required", diff --git a/src/locales/ru.json b/src/locales/ru.json index c53eff8bb..3146a61e9 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -86,6 +86,10 @@ "online": "Подключение восстановлено" }, "error": "Ошибка", + "errors": { + "something_went_wrong": "Что-то пошло не так. Детали ошибки в консоли", + "all_nodes_offline": "Все {crypto} ноды недоступны. Попробуйте позже" + }, "home": { "balance": "Баланс", "buy_tokens_anonymously": "Анонимно на сайте", @@ -313,7 +317,6 @@ "error_chat_fee": "Чтобы отправить {crypto} в чате, вам также нужно 0.001 ADM", "error_dust_amount": "Мелочь — Отправьте больше токенов", "recipient_minimum_balance": "На кошельке получателя должно быть больше 0.05 LSK — Отправьте больше токенов", - "error_all_nodes_offline": "Все {crypto} ноды недоступны. Попробуйте позже", "error_precision": "Уменьшите количество знаков после запятой", "error_erc20_fee": "Вам также нужно {fee}, чтобы оплатить комиссию", "error_field_is_required": "Поле не заполнено", diff --git a/src/locales/zh.json b/src/locales/zh.json index 835f42a2d..2ddc951fa 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -86,6 +86,10 @@ "online": "联机--已设置连接" }, "error": "错误", + "errors": { + "something_went_wrong": "Something went wrong. Check the console for details", + "all_nodes_offline": "All {crypto} nodes are offline. Try again later" + }, "home": { "balance": "余额", "buy_tokens_anonymously": "在网站上匿名", @@ -312,7 +316,6 @@ "error_chat_fee": "要通过聊天发送 {crypto},您需要 0.001 ADM", "error_dust_amount": "无存量--发送更多代币", "recipient_minimum_balance": "收件人必须至少有 0.05 LSK--发送更多令牌", - "error_all_nodes_offline": "All {crypto} nodes are offline. Try again later", "error_precision": "精度过高--设置小数位数较少", "error_erc20_fee": "您需要{费}来支付转会费", "error_field_is_required": "字段是必需的", From 8e88d9b09a3b1c307153834fe0a5976777ce19c3 Mon Sep 17 00:00:00 2001 From: bludnic Date: Fri, 9 Feb 2024 01:32:41 +0000 Subject: [PATCH 002/218] fix(nodes): handle `AllNodesOffline` error --- src/lib/bitcoin/bitcoin-api.js | 10 ++----- src/lib/bitcoin/dash-api.js | 8 ++---- src/lib/bitcoin/doge-api.js | 8 ++---- src/lib/nodes/abstract.client.ts | 26 ++++++++++++++----- src/lib/nodes/eth/EthClient.ts | 26 +++++++++++-------- src/lib/nodes/lsk-indexer/LskIndexerClient.ts | 8 +----- src/lib/nodes/lsk/LskClient.ts | 8 +----- src/store/modules/erc20/erc20-actions.js | 5 ++-- .../modules/eth-base/eth-base-actions.js | 9 +++---- src/store/modules/eth/actions.js | 18 ++++++------- src/types/utils.ts | 3 +++ 11 files changed, 58 insertions(+), 71 deletions(-) create mode 100644 src/types/utils.ts diff --git a/src/lib/bitcoin/bitcoin-api.js b/src/lib/bitcoin/bitcoin-api.js index b989361f2..1575de881 100644 --- a/src/lib/bitcoin/bitcoin-api.js +++ b/src/lib/bitcoin/bitcoin-api.js @@ -28,10 +28,7 @@ export default class BitcoinApi extends BtcBaseApi { /** @override */ sendTransaction(txHex) { - return btc - .getClient() - .post('/tx', txHex) - .then((response) => response.data) + return btc.useClient((client) => client.post('/tx', txHex)).then((response) => response.data) } /** @override */ @@ -87,9 +84,6 @@ export default class BitcoinApi extends BtcBaseApi { /** Executes a GET request to the API */ _get(url, params) { - return btc - .getClient() - .get(url, { params }) - .then((response) => response.data) + return btc.useClient((client) => client.get(url, { params })).then((response) => response.data) } } diff --git a/src/lib/bitcoin/dash-api.js b/src/lib/bitcoin/dash-api.js index f3489631e..4efd9eb26 100644 --- a/src/lib/bitcoin/dash-api.js +++ b/src/lib/bitcoin/dash-api.js @@ -95,8 +95,7 @@ export default class DashApi extends BtcBaseApi { */ _invoke(method, params) { return dash - .getClient() - .post('/', { method, params }) + .useClient((client) => client.post('/', { method, params })) .then(({ data }) => { if (data.error) throw new DashApiError(method, data.error) return data.result @@ -104,9 +103,6 @@ export default class DashApi extends BtcBaseApi { } _invokeMany(calls) { - return dash - .getClient() - .post('/', calls) - .then((response) => response.data) + return dash.useClient((client) => client.post('/', calls)).then((response) => response.data) } } diff --git a/src/lib/bitcoin/doge-api.js b/src/lib/bitcoin/doge-api.js index cc7860037..6352a1750 100644 --- a/src/lib/bitcoin/doge-api.js +++ b/src/lib/bitcoin/doge-api.js @@ -150,17 +150,13 @@ export default class DogeApi extends BtcBaseApi { /** Executes a GET request to the DOGE API */ _get(url, params) { - return doge - .getClient() - .get(url, { params }) - .then((response) => response.data) + return doge.useClient((client) => client.get(url, { params })).then((response) => response.data) } /** Executes a POST request to the DOGE API */ _post(url, data) { return doge - .getClient() - .post(url, qs.stringify(data), POST_CONFIG) + .useClient((client) => client.post(url, qs.stringify(data), POST_CONFIG)) .then((response) => response.data) } diff --git a/src/lib/nodes/abstract.client.ts b/src/lib/nodes/abstract.client.ts index b376b9687..24e392d5a 100644 --- a/src/lib/nodes/abstract.client.ts +++ b/src/lib/nodes/abstract.client.ts @@ -56,17 +56,29 @@ export abstract class Client { } } + // Use with caution: + // This method can throw an error if there are no online nodes. + // Better use "useClient()" method. getClient(): N['client'] { - const node = this.useFastest ? this.getFastestNode() : this.getRandomNode() + const node = this.getNode() - if (!node) { - console.warn(`${this.type}: No online nodes at the moment`) + return node.client + } - // Return a random one from the full list hopefully is online - return this.nodes[Math.floor(Math.random() * this.nodes.length)].client - } + /** + * Invokes a client method. + * + * eth + * .useClient((client) => client.getTransactionCount(this.$store.state.eth.address)) + * .then(res => console.log("res", res)) + * .catch(err => console.log("err", err)) + * + * @param cb + */ + async useClient(cb: (client: N['client']) => T) { + const node = this.getNode() - return node.client + return cb(node.client) } /** diff --git a/src/lib/nodes/eth/EthClient.ts b/src/lib/nodes/eth/EthClient.ts index 2c03d109e..92f773eaf 100644 --- a/src/lib/nodes/eth/EthClient.ts +++ b/src/lib/nodes/eth/EthClient.ts @@ -58,20 +58,24 @@ export class EthClient extends Client { sendSignedTransaction(...args: Parameters): Promise { return new Promise((resolve, reject) => { - this.getNode() - .client.sendSignedTransaction(...args) - .on('transactionHash', (hash) => { - if (typeof hash === 'string') { - resolve(hash) - } else { - resolve(bytesToHex(hash)) - } - }) - .on('error', reject) + try { + this.getNode() + .client.sendSignedTransaction(...args) + .on('transactionHash', (hash) => { + if (typeof hash === 'string') { + resolve(hash) + } else { + resolve(bytesToHex(hash)) + } + }) + .on('error', reject) + } catch (err) { + reject(err) + } }) } - getNonce(address: string) { + async getNonce(address: string) { return this.getNode().client.getTransactionCount(address) } } diff --git a/src/lib/nodes/lsk-indexer/LskIndexerClient.ts b/src/lib/nodes/lsk-indexer/LskIndexerClient.ts index d4cc205b3..7d759ba0a 100644 --- a/src/lib/nodes/lsk-indexer/LskIndexerClient.ts +++ b/src/lib/nodes/lsk-indexer/LskIndexerClient.ts @@ -21,13 +21,7 @@ export class LskIndexerClient extends Client { params?: Endpoints[E]['params'], axiosRequestConfig?: AxiosRequestConfig ): Promise { - const node = this.useFastest ? this.getFastestNode() : this.getRandomNode() - if (!node) { - // All nodes seem to be offline: let's refresh the statuses - this.checkHealth() - // But there's nothing we can do right now - throw new Error('No online nodes at the moment') - } + const node = this.getNode() return node.request(endpoint, params, axiosRequestConfig) } diff --git a/src/lib/nodes/lsk/LskClient.ts b/src/lib/nodes/lsk/LskClient.ts index b57afe878..a451f643c 100644 --- a/src/lib/nodes/lsk/LskClient.ts +++ b/src/lib/nodes/lsk/LskClient.ts @@ -17,13 +17,7 @@ export class LskClient extends Client { method: M, params?: RpcResults[M]['params'] ): Promise { - const node = this.useFastest ? this.getFastestNode() : this.getRandomNode() - if (!node) { - // All nodes seem to be offline: let's refresh the statuses - this.checkHealth() - // But there's nothing we can do right now - throw new Error('No online nodes at the moment') - } + const node = this.getNode() return node.invoke(method, params) } diff --git a/src/store/modules/erc20/erc20-actions.js b/src/store/modules/erc20/erc20-actions.js index 72c266ccb..e330ac154 100644 --- a/src/store/modules/erc20/erc20-actions.js +++ b/src/store/modules/erc20/erc20-actions.js @@ -16,7 +16,7 @@ const abiDecoder = new AbiDecoder(Erc20) const initTransaction = async (api, context, ethAddress, amount, nonce, increaseFee) => { const contract = new EthContract(Erc20, context.state.contractAddress) - const gasPrice = await api.getClient().getGasPrice() + const gasPrice = await api.useClient((client) => client.getGasPrice()) const transaction = { from: context.state.address, @@ -30,8 +30,7 @@ const initTransaction = async (api, context, ethAddress, amount, nonce, increase } const gasLimit = await api - .getClient() - .estimateGas(transaction) + .useClient((client) => client.estimateGas(transaction)) .catch(() => BigInt(DEFAULT_ERC20_TRANSFER_GAS_LIMIT)) transaction.gasLimit = increaseFee ? ethUtils.increaseFee(gasLimit) : gasLimit diff --git a/src/store/modules/eth-base/eth-base-actions.js b/src/store/modules/eth-base/eth-base-actions.js index 2bdf722d8..c40508b9c 100644 --- a/src/store/modules/eth-base/eth-base-actions.js +++ b/src/store/modules/eth-base/eth-base-actions.js @@ -189,8 +189,7 @@ export default function createActions(config) { if (!transaction) return void api - .getClient() - .getBlock(payload.blockNumber) + .useClient((client) => client.getBlock(payload.blockNumber)) .then((block) => { // Converting from BigInt into Number must be safe const timestamp = BigNumber(block.timestamp.toString()).multipliedBy(1000).toNumber() @@ -238,8 +237,7 @@ export default function createActions(config) { ) void api - .getClient() - .getTransaction(payload.hash) + .useClient((client) => client.getTransaction(payload.hash)) .then((tx) => { const isFinalized = tx.blockNumber !== undefined @@ -324,8 +322,7 @@ export default function createActions(config) { ) void api - .getClient() - .getTransactionReceipt(payload.hash) + .useClient((client) => client.getTransactionReceipt(payload.hash)) .then((tx) => { let replay = true diff --git a/src/store/modules/eth/actions.js b/src/store/modules/eth/actions.js index f259f32a3..b70925b10 100644 --- a/src/store/modules/eth/actions.js +++ b/src/store/modules/eth/actions.js @@ -18,7 +18,7 @@ function storeEthAddress(context) { } const initTransaction = async (api, context, ethAddress, amount, nonce, increaseFee) => { - const gasPrice = await api.getClient().getGasPrice() + const gasPrice = await api.useClient((client) => client.getGasPrice()) const transaction = { from: context.state.address, @@ -29,8 +29,7 @@ const initTransaction = async (api, context, ethAddress, amount, nonce, increase } const gasLimit = await api - .getClient() - .estimateGas(transaction) + .useClient((client) => client.estimateGas(transaction)) .catch(() => BigInt(DEFAULT_ETH_TRANSFER_GAS_LIMIT)) transaction.gasLimit = increaseFee ? utils.increaseFee(gasLimit) : gasLimit @@ -59,7 +58,9 @@ const createSpecificActions = (api) => ({ } try { - const rawBalance = await api.getClient().getBalance(state.address, 'latest') + const rawBalance = await api.useClient((client) => + client.getBalance(state.address, 'latest') + ) const balance = Number(utils.toEther(rawBalance.toString())) commit('balance', balance) @@ -80,8 +81,7 @@ const createSpecificActions = (api) => ({ // Balance void api - .getClient() - .getBalance(context.state.address, 'latest') + .useClient((client) => client.getBalance(context.state.address, 'latest')) .then((balance) => { context.commit('balance', Number(utils.toEther(balance.toString()))) context.commit('setBalanceStatus', FetchStatus.Success) @@ -89,8 +89,7 @@ const createSpecificActions = (api) => ({ // Current gas price void api - .getClient() - .getGasPrice() + .useClient((client) => client.getGasPrice()) .then((price) => { context.commit('gasPrice', { gasPrice: Number(price), @@ -100,8 +99,7 @@ const createSpecificActions = (api) => ({ // Current block number void api - .getClient() - .getBlockNumber() + .useClient((client) => client.getBlockNumber()) .then((number) => { context.commit('blockNumber', Number(number)) }) diff --git a/src/types/utils.ts b/src/types/utils.ts new file mode 100644 index 000000000..22b6b7e91 --- /dev/null +++ b/src/types/utils.ts @@ -0,0 +1,3 @@ +export type ExtractMethods = { + [K in keyof T]: T[K] extends (...args: any[]) => infer R ? R : never +} From 0bbba2f6287904e4f1dad2b061750cf671dde64d Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 10 Feb 2024 23:28:30 +0000 Subject: [PATCH 003/218] feat(Chat): add NodesOfflineDialog --- src/components/NodesOfflineDialog.vue | 67 +++++++++++++++++++++++++++ src/locales/en.json | 7 ++- src/locales/ru.json | 7 ++- src/locales/zh.json | 7 ++- src/views/Chat.vue | 4 ++ 5 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 src/components/NodesOfflineDialog.vue diff --git a/src/components/NodesOfflineDialog.vue b/src/components/NodesOfflineDialog.vue new file mode 100644 index 000000000..efdeea9b5 --- /dev/null +++ b/src/components/NodesOfflineDialog.vue @@ -0,0 +1,67 @@ + + + diff --git a/src/locales/en.json b/src/locales/en.json index 71444466c..4b89ade84 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -79,7 +79,12 @@ "you_reacted": "Reacted", "partner_reacted": "Reacted", "you_removed_reaction": "Removed reaction", - "partner_removed_reaction": "Removed reaction" + "partner_removed_reaction": "Removed reaction", + "nodes_offline_dialog": { + "title": "Nodes are offline", + "text": "All {coin} nodes appear to be offline or possibly disabled. To continue use the Messenger please review the Nodes list and enable any nodes that are found to be disabled.", + "open_nodes_button": "Open Nodes page" + } }, "connection": { "offline": "Offline—No connection", diff --git a/src/locales/ru.json b/src/locales/ru.json index 3146a61e9..d81c760db 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -79,7 +79,12 @@ "you_reacted": "Отреагировали", "partner_reacted": "Отреагировал", "you_removed_reaction": "Убрали реакцию", - "partner_removed_reaction": "Убрал реакцию" + "partner_removed_reaction": "Убрал реакцию", + "nodes_offline_dialog": { + "title": "Узлы недоступны", + "text": "Кажется все узлы {coin} недоступны, или возможно отключены. Перейдите на страницу Узлов и включите узлы, если они отключены.", + "open_nodes_button": "Перейти в Список узлов" + } }, "connection": { "offline": "Нет подключения к Интернету", diff --git a/src/locales/zh.json b/src/locales/zh.json index 2ddc951fa..825fcb4e3 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -79,7 +79,12 @@ "you_reacted": "Reacted", "partner_reacted": "已反应", "you_removed_reaction": "已删除反应", - "partner_removed_reaction": "已删除的反应" + "partner_removed_reaction": "已删除的反应", + "nodes_offline_dialog": { + "title": "Nodes are offline", + "text": "All {coin} nodes appear to be offline or possibly disabled. To continue use the Messenger please review the Nodes list and enable any nodes that are found to be disabled.", + "open_nodes_button": "Open Nodes page" + } }, "connection": { "offline": "Offline—无连接", diff --git a/src/views/Chat.vue b/src/views/Chat.vue index c18de16e2..59edf1cf7 100644 --- a/src/views/Chat.vue +++ b/src/views/Chat.vue @@ -17,10 +17,13 @@ + + diff --git a/src/components/transactions/BtcTransaction.vue b/src/components/transactions/BtcTransaction.vue index 4410913c6..e37c2a625 100644 --- a/src/components/transactions/BtcTransaction.vue +++ b/src/components/transactions/BtcTransaction.vue @@ -11,8 +11,8 @@ :sender-formatted="senderFormatted || ''" :recipient-formatted="recipientFormatted || ''" :explorer-link="explorerLink" - :partner="partner || ''" - :status="getTransactionStatus(admTx, transaction)" + :partner="partnerAdmAddress || ''" + :status="status" :adm-tx="admTx" :crypto="crypto" /> @@ -20,36 +20,61 @@ diff --git a/src/components/transactions/Erc20Transaction.vue b/src/components/transactions/Erc20Transaction.vue index 0606b397b..9e3950db2 100644 --- a/src/components/transactions/Erc20Transaction.vue +++ b/src/components/transactions/Erc20Transaction.vue @@ -10,24 +10,30 @@ :sender-formatted="senderFormatted || ''" :recipient-formatted="recipientFormatted || ''" :explorer-link="explorerLink" - :partner="partner || ''" - :status="getTransactionStatus(admTx, transaction)" + :partner="partnerAdmAddress || ''" + :status="status" :adm-tx="admTx" :crypto="crypto" /> diff --git a/src/components/transactions/EthTransaction.vue b/src/components/transactions/EthTransaction.vue index e6ef158dd..c4a84adff 100644 --- a/src/components/transactions/EthTransaction.vue +++ b/src/components/transactions/EthTransaction.vue @@ -11,28 +11,30 @@ :recipient-formatted="recipientFormatted || ''" :explorer-link="explorerLink" :partner="partner || ''" - :status="getTransactionStatus(admTx, transaction)" + :status="status" :adm-tx="admTx" :crypto="crypto" /> diff --git a/src/components/transactions/LskTransaction.vue b/src/components/transactions/LskTransaction.vue index 63abd68ed..9475811b8 100644 --- a/src/components/transactions/LskTransaction.vue +++ b/src/components/transactions/LskTransaction.vue @@ -10,8 +10,8 @@ :sender-formatted="senderFormatted || ''" :recipient-formatted="recipientFormatted || ''" :explorer-link="explorerLink" - :partner="partner || ''" - :status="getTransactionStatus(admTx, transaction)" + :partner="partnerAdmAddress || ''" + :status="status" :adm-tx="admTx" :crypto="crypto" :text-data="transaction.data || ''" @@ -19,21 +19,23 @@ diff --git a/src/hooks/address/useFindAdmAddress.ts b/src/hooks/address/useFindAdmAddress.ts new file mode 100644 index 000000000..74288c5d8 --- /dev/null +++ b/src/hooks/address/useFindAdmAddress.ts @@ -0,0 +1,60 @@ +import { computed, MaybeRef, Ref, unref } from 'vue' +import { useStore } from 'vuex' +import { isStringEqualCI } from '@/lib/textHelpers' + +/** + * Find ADM address by cryptoAddress or transactionHash + * + * 1. Scan partners module first + * 2. If not found, scan chat messages + * + * @param crypto - Crypto symbol e.g. 'btc' | 'eth' + * @param cryptoAddress - Crypto address + * @param transactionHash - Transaction hash + */ +export function useFindAdmAddress( + crypto: Ref, + cryptoAddress: MaybeRef, + transactionHash: MaybeRef +) { + const store = useStore() + + return computed(() => { + let admAddress = '' + + const cryptoAddressValue = unref(cryptoAddress) + const transactionHashValue = unref(transactionHash) + + // First, check the known partners + const partners = store.state.partners + Object.keys(partners).some((uid) => { + const partner = partners[uid] + if (isStringEqualCI(partner[crypto.value], cryptoAddressValue)) { + admAddress = uid + } + return !!admAddress + }) + + if (!admAddress) { + // Bad news, everyone: we'll have to scan the messages + Object.values(store.state.chat.chats).some((chat) => { + // @ts-expect-error-next-line + Object.values(chat.messages).some((msg) => { + // @ts-expect-error-next-line + if (msg.hash && msg.hash === transactionHashValue) { + // @ts-expect-error-next-line + admAddress = isStringEqualCI(msg.senderId, store.state.address) + ? // @ts-expect-error-next-line + msg.recipientId + : // @ts-expect-error-next-line + msg.senderId + } + return !!admAddress + }) + return !!admAddress + }) + } + + return admAddress + }) +} diff --git a/src/hooks/address/useFormatADMAddress.ts b/src/hooks/address/useFormatADMAddress.ts new file mode 100644 index 000000000..8b4fe1051 --- /dev/null +++ b/src/hooks/address/useFormatADMAddress.ts @@ -0,0 +1,36 @@ +import { formatADMAddress } from '@/utils/address' +import { computed, MaybeRef, unref } from 'vue' +import { useI18n } from 'vue-i18n' +import { useStore } from 'vuex' +import { isStringEqualCI } from '@/lib/textHelpers' +import { useChatName } from '@/components/AChat/hooks/useChatName' + +/** + * Formats the user address. + * + * Examples: + * + * - Me (U1234567890) + * - Jon (U0987654321) + * + * @param address ADM address + */ +export function useFormatADMAddress(address: MaybeRef) { + const store = useStore() + const { t } = useI18n() + + const chatName = useChatName(address) + + return computed(() => { + const addressValue = unref(address) + + let name = '' + if (isStringEqualCI(addressValue, store.state.address)) { + name = t('transaction.me') + } else { + name = chatName.value + } + + return formatADMAddress(addressValue, name) + }) +} diff --git a/src/hooks/address/usePartnerCryptoAddress.ts b/src/hooks/address/usePartnerCryptoAddress.ts new file mode 100644 index 000000000..c93e9999a --- /dev/null +++ b/src/hooks/address/usePartnerCryptoAddress.ts @@ -0,0 +1,15 @@ +import { isStringEqualCI } from '@/lib/textHelpers' +import { computed, MaybeRef, Ref, unref } from 'vue' + +export function usePartnerCryptoAddress( + ownAddress: Ref, + senderId: MaybeRef, + recipientId: MaybeRef +) { + return computed(() => { + const senderIdValue = unref(senderId) + const recipientIdValue = unref(recipientId) + + return isStringEqualCI(senderIdValue, ownAddress.value) ? recipientIdValue : senderIdValue + }) +} From 6c53c9ac45bb647722b51bf690d59f6f3cfe3277 Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 14 Feb 2024 01:12:44 +0000 Subject: [PATCH 009/218] refactor(address): rename `formatBTCAddress` -> `formatCryptoAddress` --- .../transactions/BtcTransaction.vue | 6 ++-- .../transactions/Erc20Transaction.vue | 6 ++-- .../transactions/EthTransaction.vue | 6 ++-- .../transactions/LskTransaction.vue | 6 ++-- ...ss.spec.ts => formatCryptoAddress.spec.ts} | 34 +++++++++++++------ ...atBTCAddress.ts => formatCryptoAddress.ts} | 18 +++++----- src/utils/address/index.ts | 2 +- 7 files changed, 45 insertions(+), 33 deletions(-) rename src/utils/address/{formatBTCAddress.spec.ts => formatCryptoAddress.spec.ts} (50%) rename src/utils/address/{formatBTCAddress.ts => formatCryptoAddress.ts} (57%) diff --git a/src/components/transactions/BtcTransaction.vue b/src/components/transactions/BtcTransaction.vue index e37c2a625..119afc81e 100644 --- a/src/components/transactions/BtcTransaction.vue +++ b/src/components/transactions/BtcTransaction.vue @@ -27,7 +27,7 @@ import { useChatName } from '@/components/AChat/hooks/useChatName' import { useFindAdmAddress } from '@/hooks/address/useFindAdmAddress' import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress' import { useTransactionStatus } from '@/hooks/useTransactionStatus' -import { formatBTCAddress, formatMultipleBTCAddresses } from '@/utils/address' +import { formatCryptoAddress, formatMultipleBTCAddresses } from '@/utils/address' import TransactionTemplate from './TransactionTemplate.vue' import { getExplorerTxUrl } from '@/config/utils' import { CryptosInfo } from '@/lib/constants' @@ -101,7 +101,7 @@ export default defineComponent({ const { senders, senderId } = transaction.value const onlySender = senderId && (!senders || senders.length === 1) if (onlySender) { - return formatBTCAddress( + return formatCryptoAddress( senderId, cryptoAddress.value, t, @@ -119,7 +119,7 @@ export default defineComponent({ const { recipientId, recipients } = transaction.value const onlyRecipient = recipientId && (!recipients || recipients.length === 1) if (onlyRecipient) { - return formatBTCAddress( + return formatCryptoAddress( recipientId, cryptoAddress.value, t, diff --git a/src/components/transactions/Erc20Transaction.vue b/src/components/transactions/Erc20Transaction.vue index 9e3950db2..558a0154b 100644 --- a/src/components/transactions/Erc20Transaction.vue +++ b/src/components/transactions/Erc20Transaction.vue @@ -29,7 +29,7 @@ import { useTransactionStatus } from '@/hooks/useTransactionStatus' import { useChatName } from '@/components/AChat/hooks/useChatName' import { useFindAdmAddress } from '@/hooks/address/useFindAdmAddress' import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress' -import { formatBTCAddress } from '@/utils/address' +import { formatCryptoAddress } from '@/utils/address' import transaction from '@/mixins/transaction' import currency from '@/filters/currencyAmountWithSymbol' @@ -70,7 +70,7 @@ export default defineComponent({ const recipientName = useChatName(recipientAdmAddress.value) const senderFormatted = computed(() => { - return formatBTCAddress( + return formatCryptoAddress( transaction.value.senderId, cryptoAddress.value, t, @@ -79,7 +79,7 @@ export default defineComponent({ ) }) const recipientFormatted = computed(() => { - return formatBTCAddress( + return formatCryptoAddress( transaction.value.recipientId, cryptoAddress.value, t, diff --git a/src/components/transactions/EthTransaction.vue b/src/components/transactions/EthTransaction.vue index c4a84adff..8ec769870 100644 --- a/src/components/transactions/EthTransaction.vue +++ b/src/components/transactions/EthTransaction.vue @@ -29,7 +29,7 @@ import { useChatName } from '@/components/AChat/hooks/useChatName' import { useFindAdmAddress } from '@/hooks/address/useFindAdmAddress' import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress' import { useTransactionStatus } from '@/hooks/useTransactionStatus' -import { formatBTCAddress } from '@/utils/address' +import { formatCryptoAddress } from '@/utils/address' export default defineComponent({ components: { @@ -67,7 +67,7 @@ export default defineComponent({ const recipientName = useChatName(recipientAdmAddress.value) const senderFormatted = computed(() => { - return formatBTCAddress( + return formatCryptoAddress( transaction.value.senderId, cryptoAddress.value, t, @@ -76,7 +76,7 @@ export default defineComponent({ ) }) const recipientFormatted = computed(() => { - return formatBTCAddress( + return formatCryptoAddress( transaction.value.recipientId, cryptoAddress.value, t, diff --git a/src/components/transactions/LskTransaction.vue b/src/components/transactions/LskTransaction.vue index 9475811b8..77420d122 100644 --- a/src/components/transactions/LskTransaction.vue +++ b/src/components/transactions/LskTransaction.vue @@ -29,7 +29,7 @@ import { useChatName } from '@/components/AChat/hooks/useChatName' import { useFindAdmAddress } from '@/hooks/address/useFindAdmAddress' import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress' import { useTransactionStatus } from '@/hooks/useTransactionStatus' -import { formatBTCAddress } from '@/utils/address' +import { formatCryptoAddress } from '@/utils/address' import currency from '@/filters/currencyAmountWithSymbol' export default defineComponent({ @@ -69,7 +69,7 @@ export default defineComponent({ const recipientName = useChatName(recipientAdmAddress) const senderFormatted = computed(() => { - return formatBTCAddress( + return formatCryptoAddress( transaction.value.senderId, cryptoAddress.value, t, @@ -78,7 +78,7 @@ export default defineComponent({ ) }) const recipientFormatted = computed(() => { - return formatBTCAddress( + return formatCryptoAddress( transaction.value.recipientId, cryptoAddress.value, t, diff --git a/src/utils/address/formatBTCAddress.spec.ts b/src/utils/address/formatCryptoAddress.spec.ts similarity index 50% rename from src/utils/address/formatBTCAddress.spec.ts rename to src/utils/address/formatCryptoAddress.spec.ts index ce0fb5a31..401ad002c 100644 --- a/src/utils/address/formatBTCAddress.spec.ts +++ b/src/utils/address/formatCryptoAddress.spec.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from 'vitest' -import { formatBTCAddress } from './formatBTCAddress' +import { formatCryptoAddress } from './formatCryptoAddress' -const OWN_BTC_ADDRESS = '1EQuRM9nKdzUFUadUXKcaHQCeMR5eGsWwP' +const OWN_CRYPTO_ADDRESS = '1EQuRM9nKdzUFUadUXKcaHQCeMR5eGsWwP' -const PARTNER_BTC_ADDRESS = '16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3' +const PARTNER_CRYPTO_ADDRESS = '16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3' const PARTNER_ADM_ADDRESS = 'U0987654321' const translations: Record = { @@ -15,34 +15,46 @@ const tFunction = (key: string) => { return translation || key } -describe('formatBTCAddress', () => { +describe('formatCryptoAddress', () => { it('should format own BTC address', () => { - expect(formatBTCAddress(OWN_BTC_ADDRESS, OWN_BTC_ADDRESS, tFunction)).toBe( + expect(formatCryptoAddress(OWN_CRYPTO_ADDRESS, OWN_CRYPTO_ADDRESS, tFunction)).toBe( `Me (1EQuRM9nKdzUFUadUXKcaHQCeMR5eGsWwP)` ) }) it('should format single BTC address without chat name', () => { - expect(formatBTCAddress(PARTNER_BTC_ADDRESS, OWN_BTC_ADDRESS, tFunction)).toBe( + expect(formatCryptoAddress(PARTNER_CRYPTO_ADDRESS, OWN_CRYPTO_ADDRESS, tFunction)).toBe( '16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3' ) }) it('should format single BTC address with chat name', () => { - expect(formatBTCAddress(PARTNER_BTC_ADDRESS, OWN_BTC_ADDRESS, tFunction, '', 'John')).toBe( - 'John (16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3)' - ) + expect( + formatCryptoAddress(PARTNER_CRYPTO_ADDRESS, OWN_CRYPTO_ADDRESS, tFunction, '', 'John') + ).toBe('John (16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3)') }) it('should format single BTC address with ADM address provided', () => { expect( - formatBTCAddress(PARTNER_BTC_ADDRESS, OWN_BTC_ADDRESS, tFunction, PARTNER_ADM_ADDRESS, '') + formatCryptoAddress( + PARTNER_CRYPTO_ADDRESS, + OWN_CRYPTO_ADDRESS, + tFunction, + PARTNER_ADM_ADDRESS, + '' + ) ).toBe(`16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3 (U0987654321)`) }) it('should use the chat name if both, chat name and ADM address provided', () => { expect( - formatBTCAddress(PARTNER_BTC_ADDRESS, OWN_BTC_ADDRESS, tFunction, PARTNER_ADM_ADDRESS, 'John') + formatCryptoAddress( + PARTNER_CRYPTO_ADDRESS, + OWN_CRYPTO_ADDRESS, + tFunction, + PARTNER_ADM_ADDRESS, + 'John' + ) ).toBe(`John (16ADr4P8s2BssFKhJdQ9gRMDR7oSZ289C3)`) }) }) diff --git a/src/utils/address/formatBTCAddress.ts b/src/utils/address/formatCryptoAddress.ts similarity index 57% rename from src/utils/address/formatBTCAddress.ts rename to src/utils/address/formatCryptoAddress.ts index 5d547136a..227c711c6 100644 --- a/src/utils/address/formatBTCAddress.ts +++ b/src/utils/address/formatCryptoAddress.ts @@ -1,24 +1,24 @@ import { isStringEqualCI } from '@/lib/textHelpers' /** - * Formats BTC address. + * Formats a crypto address * - * @param btcAddress BTC address - * @param ownBtcAddress BTC address of the current account + * @param cryptoAddress Crypto address to format + * @param ownCryptoAddress Crypto address of the current account * @param t TFunction from `vue-i18n` * @param admAddress ADM address * @param partnerName Chat name */ -export function formatBTCAddress( - btcAddress: string, - ownBtcAddress: string, +export function formatCryptoAddress( + cryptoAddress: string, + ownCryptoAddress: string, t: (key: string) => string, admAddress = '', partnerName = '' ) { let name = '' - const isMineAddress = isStringEqualCI(btcAddress, ownBtcAddress) + const isMineAddress = isStringEqualCI(cryptoAddress, ownCryptoAddress) if (isMineAddress) { name = t('transaction.me') @@ -28,9 +28,9 @@ export function formatBTCAddress( let result = '' if (name !== '' && name !== undefined) { - result = name + ' (' + btcAddress + ')' + result = name + ' (' + cryptoAddress + ')' } else { - result = btcAddress + result = cryptoAddress if (admAddress) { result += ' (' + admAddress + ')' } diff --git a/src/utils/address/index.ts b/src/utils/address/index.ts index 8eed94e39..43a6f245c 100644 --- a/src/utils/address/index.ts +++ b/src/utils/address/index.ts @@ -1,3 +1,3 @@ export * from './formatADMAddress' -export * from './formatBTCAddress' +export * from './formatCryptoAddress' export * from './formatMultipleBTCAddresses' From ce2109137269627cf564d44589bcebc479b847bd Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 14 Feb 2024 01:21:59 +0000 Subject: [PATCH 010/218] refactor(transactions): add `useFindAdmTransaction` hook --- .../transactions/BtcTransaction.vue | 17 ++--------- .../transactions/Erc20Transaction.vue | 17 ++--------- .../transactions/EthTransaction.vue | 17 ++--------- .../transactions/LskTransaction.vue | 16 ++--------- src/hooks/address/index.ts | 4 +++ src/hooks/address/useFindAdmTransaction.ts | 28 +++++++++++++++++++ 6 files changed, 42 insertions(+), 57 deletions(-) create mode 100644 src/hooks/address/index.ts create mode 100644 src/hooks/address/useFindAdmTransaction.ts diff --git a/src/components/transactions/BtcTransaction.vue b/src/components/transactions/BtcTransaction.vue index 119afc81e..7f8763573 100644 --- a/src/components/transactions/BtcTransaction.vue +++ b/src/components/transactions/BtcTransaction.vue @@ -31,6 +31,7 @@ import { formatCryptoAddress, formatMultipleBTCAddresses } from '@/utils/address import TransactionTemplate from './TransactionTemplate.vue' import { getExplorerTxUrl } from '@/config/utils' import { CryptosInfo } from '@/lib/constants' +import { useFindAdmTransaction } from '@/hooks/address' import currency from '@/filters/currencyAmountWithSymbol' @@ -150,21 +151,7 @@ export default defineComponent({ return result }) - const admTx = computed(() => { - const admTx = {} - // Bad news, everyone: we'll have to scan the messages - Object.values(store.state.chat.chats).some((chat) => { - Object.values(chat.messages).some((msg) => { - if (msg.hash && msg.hash === props.id) { - Object.assign(admTx, msg) - } - return !!admTx.id - }) - return !!admTx.id - }) - - return admTx - }) + const admTx = useFindAdmTransaction(props.id) const status = useTransactionStatus(admTx, transaction) diff --git a/src/components/transactions/Erc20Transaction.vue b/src/components/transactions/Erc20Transaction.vue index 558a0154b..010b921c7 100644 --- a/src/components/transactions/Erc20Transaction.vue +++ b/src/components/transactions/Erc20Transaction.vue @@ -32,6 +32,7 @@ import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress import { formatCryptoAddress } from '@/utils/address' import transaction from '@/mixins/transaction' import currency from '@/filters/currencyAmountWithSymbol' +import { useFindAdmTransaction } from '@/hooks/address' export default defineComponent({ name: 'Erc20Transaction', @@ -100,20 +101,8 @@ export default defineComponent({ if (!transaction.value.blockNumber || !store.state.eth.blockNumber) return 0 return Math.max(0, store.state.eth.blockNumber - transaction.value.blockNumber) }) - const admTx = computed(() => { - const admTx = {} - // Bad news, everyone: we'll have to scan the messages - Object.values(store.state.chat.chats).some((chat) => { - Object.values(chat.messages).some((msg) => { - if (msg.hash && msg.hash === props.id) { - Object.assign(admTx, msg) - } - return !!admTx.id - }) - return !!admTx.id - }) - return admTx - }) + const admTx = useFindAdmTransaction(props.id) + const status = useTransactionStatus(admTx, transaction) return { diff --git a/src/components/transactions/EthTransaction.vue b/src/components/transactions/EthTransaction.vue index 8ec769870..aba330ce4 100644 --- a/src/components/transactions/EthTransaction.vue +++ b/src/components/transactions/EthTransaction.vue @@ -30,6 +30,7 @@ import { useFindAdmAddress } from '@/hooks/address/useFindAdmAddress' import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress' import { useTransactionStatus } from '@/hooks/useTransactionStatus' import { formatCryptoAddress } from '@/utils/address' +import { useFindAdmTransaction } from '@/hooks/address' export default defineComponent({ components: { @@ -97,20 +98,8 @@ export default defineComponent({ if (!transaction.value.blockNumber || !store.state.eth.blockNumber) return 0 return Math.max(0, store.state.eth.blockNumber - transaction.value.blockNumber) }) - const admTx = computed(() => { - const admTx = {} - // Bad news, everyone: we'll have to scan the messages - Object.values(store.state.chat.chats).some((chat) => { - Object.values(chat.messages).some((msg) => { - if (msg.hash && msg.hash === props.id) { - Object.assign(admTx, msg) - } - return !!admTx.id - }) - return !!admTx.id - }) - return admTx - }) + const admTx = useFindAdmTransaction(props.id) + const status = useTransactionStatus(admTx, transaction) return { diff --git a/src/components/transactions/LskTransaction.vue b/src/components/transactions/LskTransaction.vue index 77420d122..ad3d5c7e9 100644 --- a/src/components/transactions/LskTransaction.vue +++ b/src/components/transactions/LskTransaction.vue @@ -31,6 +31,7 @@ import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress import { useTransactionStatus } from '@/hooks/useTransactionStatus' import { formatCryptoAddress } from '@/utils/address' import currency from '@/filters/currencyAmountWithSymbol' +import { useFindAdmTransaction } from '@/hooks/address' export default defineComponent({ components: { @@ -106,20 +107,7 @@ export default defineComponent({ return currentHeight - height + 1 }) - const admTx = computed(() => { - const admTx = {} - // Bad news, everyone: we'll have to scan the messages - Object.values(store.state.chat.chats).some((chat) => { - Object.values(chat.messages).some((msg) => { - if (msg.hash && msg.hash === props.id) { - Object.assign(admTx, msg) - } - return !!admTx.id - }) - return !!admTx.id - }) - return admTx - }) + const admTx = useFindAdmTransaction(props.id) const status = useTransactionStatus(admTx, transaction) diff --git a/src/hooks/address/index.ts b/src/hooks/address/index.ts new file mode 100644 index 000000000..caacbcb1c --- /dev/null +++ b/src/hooks/address/index.ts @@ -0,0 +1,4 @@ +export * from './useFindAdmAddress' +export * from './useFindAdmTransaction' +export * from './useFormatADMAddress' +export * from './usePartnerCryptoAddress' diff --git a/src/hooks/address/useFindAdmTransaction.ts b/src/hooks/address/useFindAdmTransaction.ts new file mode 100644 index 000000000..2b512e0be --- /dev/null +++ b/src/hooks/address/useFindAdmTransaction.ts @@ -0,0 +1,28 @@ +import { computed, MaybeRef, unref } from 'vue' +import { useStore } from 'vuex' + +/** + * Find ADM special message by transactionHash in the chat messages + */ +export function useFindAdmTransaction(hash: MaybeRef) { + const store = useStore() + + return computed(() => { + const hashValue = unref(hash) + + const admTx = {} as any + // Bad news, everyone: we'll have to scan the messages + Object.values(store.state.chat.chats).some((chat) => { + // @ts-expect-error-next-line + Object.values(chat.messages).some((msg) => { + // @ts-expect-error-next-line + if (msg.hash && msg.hash === hashValue) { + Object.assign(admTx, msg) + } + return !!admTx.id + }) + return !!admTx.id + }) + return admTx + }) +} From 666a371a009e6f49b0480a784cf37a474fa9d073 Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 14 Feb 2024 03:10:43 +0000 Subject: [PATCH 011/218] fix(Erc20Transaction): remove unused mixins --- src/components/transactions/Erc20Transaction.vue | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/transactions/Erc20Transaction.vue b/src/components/transactions/Erc20Transaction.vue index 010b921c7..27c473404 100644 --- a/src/components/transactions/Erc20Transaction.vue +++ b/src/components/transactions/Erc20Transaction.vue @@ -24,13 +24,11 @@ import { useStore } from 'vuex' import TransactionTemplate from './TransactionTemplate.vue' import { getExplorerTxUrl } from '@/config/utils' import { Cryptos } from '../../lib/constants' -import partnerName from '@/mixins/partnerName' import { useTransactionStatus } from '@/hooks/useTransactionStatus' import { useChatName } from '@/components/AChat/hooks/useChatName' import { useFindAdmAddress } from '@/hooks/address/useFindAdmAddress' import { usePartnerCryptoAddress } from '@/hooks/address/usePartnerCryptoAddress' import { formatCryptoAddress } from '@/utils/address' -import transaction from '@/mixins/transaction' import currency from '@/filters/currencyAmountWithSymbol' import { useFindAdmTransaction } from '@/hooks/address' @@ -39,7 +37,6 @@ export default defineComponent({ components: { TransactionTemplate }, - mixins: [transaction, partnerName], props: { crypto: { required: true, From b8229d473ba8b9d5283b645550186d72c20bca3e Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 14 Feb 2024 04:00:22 +0000 Subject: [PATCH 012/218] refactor(TransactionTemplate): convert into Composition API --- .../transactions/AdmTransaction.vue | 2 +- .../transactions/BtcTransaction.vue | 2 +- .../transactions/Erc20Transaction.vue | 2 +- .../transactions/EthTransaction.vue | 2 +- .../transactions/LskTransaction.vue | 2 +- .../transactions/TransactionTemplate.vue | 203 ++++++++++-------- src/hooks/useTransactionStatus.ts | 39 +++- 7 files changed, 161 insertions(+), 91 deletions(-) diff --git a/src/components/transactions/AdmTransaction.vue b/src/components/transactions/AdmTransaction.vue index 8b26823cc..d435d5f8b 100644 --- a/src/components/transactions/AdmTransaction.vue +++ b/src/components/transactions/AdmTransaction.vue @@ -60,7 +60,7 @@ export default defineComponent({ }) const explorerLink = computed(() => getExplorerTxUrl(Cryptos.ADM, props.id)) - const status = useTransactionStatus(admTx, undefined) + const { status } = useTransactionStatus(admTx, undefined) return { transaction, diff --git a/src/components/transactions/BtcTransaction.vue b/src/components/transactions/BtcTransaction.vue index 7f8763573..c75a50904 100644 --- a/src/components/transactions/BtcTransaction.vue +++ b/src/components/transactions/BtcTransaction.vue @@ -153,7 +153,7 @@ export default defineComponent({ const admTx = useFindAdmTransaction(props.id) - const status = useTransactionStatus(admTx, transaction) + const { status } = useTransactionStatus(admTx, transaction) return { transaction, diff --git a/src/components/transactions/Erc20Transaction.vue b/src/components/transactions/Erc20Transaction.vue index 27c473404..31e55d04f 100644 --- a/src/components/transactions/Erc20Transaction.vue +++ b/src/components/transactions/Erc20Transaction.vue @@ -100,7 +100,7 @@ export default defineComponent({ }) const admTx = useFindAdmTransaction(props.id) - const status = useTransactionStatus(admTx, transaction) + const { status } = useTransactionStatus(admTx, transaction) return { sender, diff --git a/src/components/transactions/EthTransaction.vue b/src/components/transactions/EthTransaction.vue index aba330ce4..3484e0dba 100644 --- a/src/components/transactions/EthTransaction.vue +++ b/src/components/transactions/EthTransaction.vue @@ -100,7 +100,7 @@ export default defineComponent({ }) const admTx = useFindAdmTransaction(props.id) - const status = useTransactionStatus(admTx, transaction) + const { status } = useTransactionStatus(admTx, transaction) return { sender, diff --git a/src/components/transactions/LskTransaction.vue b/src/components/transactions/LskTransaction.vue index ad3d5c7e9..0c7dbf953 100644 --- a/src/components/transactions/LskTransaction.vue +++ b/src/components/transactions/LskTransaction.vue @@ -109,7 +109,7 @@ export default defineComponent({ const admTx = useFindAdmTransaction(props.id) - const status = useTransactionStatus(admTx, transaction) + const { status } = useTransactionStatus(admTx, transaction) return { transaction, diff --git a/src/components/transactions/TransactionTemplate.vue b/src/components/transactions/TransactionTemplate.vue index e69d06b93..fffa88244 100644 --- a/src/components/transactions/TransactionTemplate.vue +++ b/src/components/transactions/TransactionTemplate.vue @@ -50,7 +50,9 @@ {{ $t('transaction.status') }} diff --git a/src/components/nodes/services/ServiceNodesTableItem.vue b/src/components/nodes/services/ServiceNodesTableItem.vue new file mode 100644 index 000000000..6c54133d5 --- /dev/null +++ b/src/components/nodes/services/ServiceNodesTableItem.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/src/lib/nodes/abstract.node.ts b/src/lib/nodes/abstract.node.ts index 193049507..0b003b8d0 100644 --- a/src/lib/nodes/abstract.node.ts +++ b/src/lib/nodes/abstract.node.ts @@ -1,13 +1,8 @@ import { getHealthCheckInterval } from './utils/getHealthcheckConfig' import { TNodeLabel } from './constants' -import { HealthcheckInterval, NodeKind, NodeStatus, NodeType } from './types' +import { HealthcheckInterval, HealthcheckResult, NodeKind, NodeStatus, NodeType } from './types' import { nodesStorage } from './storage' -type HealthcheckResult = { - height: number - ping: number -} - type HttpProtocol = 'http:' | 'https:' type WsProtocol = 'ws:' | 'wss:' diff --git a/src/lib/nodes/rate-info-service/RateInfoClient.ts b/src/lib/nodes/rate-info-service/RateInfoClient.ts new file mode 100644 index 000000000..eaa89ba31 --- /dev/null +++ b/src/lib/nodes/rate-info-service/RateInfoClient.ts @@ -0,0 +1,33 @@ +import { Client } from '@/lib/nodes/abstract.client.ts' +import { RateInfoResponse, RateInfoService } from '@/lib/nodes/rate-info-service/RateInfoService.ts' + +export class RateInfoClient extends Client { + constructor(endpoints: string[] = [], minNodeVersion = '0.0.0') { + super('adm') + this.nodes = endpoints.map((endpoint) => new RateInfoService(endpoint)) + this.minNodeVersion = minNodeVersion + + void this.watchNodeStatusChange() + } + + async getAllRates(): Promise { + const node = await this.fetchNode() + return await node.getAllRates() + } + + async getHistory(timestamp: number) { + const node = await this.fetchNode() + return await node.getHistory(timestamp) + } + + async fetchNode() { + const node = this.useFastest ? this.getFastestNode() : this.getRandomNode() + if (!node) { + // All nodes seem to be offline: let's refresh the statuses + this.checkHealth() + // But there's nothing we can do right now + return Promise.reject(new Error('No online nodes at the moment')) + } + return node + } +} diff --git a/src/lib/nodes/rate-info-service/RateInfoService.ts b/src/lib/nodes/rate-info-service/RateInfoService.ts new file mode 100644 index 000000000..0cd90a8e8 --- /dev/null +++ b/src/lib/nodes/rate-info-service/RateInfoService.ts @@ -0,0 +1,52 @@ +import { Node } from '@/lib/nodes/abstract.node' +import axios, { AxiosInstance } from 'axios' +import { HealthcheckResult } from '@/lib/nodes/types.ts' +import { NODE_LABELS } from '@/lib/nodes/constants.ts' + +export type RateInfoResponse = { + success: boolean + date: number + result: Record +} + +export type RateHistoryInfoResponse = { + success: boolean + date: number + result: { + _id: string + date: number + tickers: Record + }[] +} + +export class RateInfoService extends Node { + constructor(url: string) { + super(url, 'adm', 'service', NODE_LABELS.RatesInfo) + } + protected buildClient(): AxiosInstance { + return axios.create({ + baseURL: this.url + }) + } + + async getAllRates(): Promise { + const response = await this.client.get('/get') + return response.data + } + + async getHistory(timestamp: number) { + const response = await this.client.get( + `/getHistory?timestamp=${timestamp}` + ) + return response.data + } + + protected async checkHealth(): Promise { + const start = Date.now() + const response = await this.getAllRates() + return { + ping: Date.now() - start, + height: response.date + } + } +} diff --git a/src/lib/nodes/rate-info-service/index.ts b/src/lib/nodes/rate-info-service/index.ts new file mode 100644 index 000000000..00e4522ba --- /dev/null +++ b/src/lib/nodes/rate-info-service/index.ts @@ -0,0 +1,10 @@ +import config from '@/config' +import { NodeInfo } from '@/types/wallets' +import { RateInfoClient } from '@/lib/nodes/rate-info-service/RateInfoClient.ts' + +const endpoints = (config.adm.services.list.infoService as NodeInfo[]).map( + (endpoint) => endpoint.url +) +export const rateInfoClient = new RateInfoClient(endpoints) + +export default rateInfoClient diff --git a/src/lib/nodes/services.ts b/src/lib/nodes/services.ts index ee2688adf..a271b285e 100644 --- a/src/lib/nodes/services.ts +++ b/src/lib/nodes/services.ts @@ -1,7 +1,9 @@ import { lskIndexer } from './lsk-indexer' import { ethIndexer } from './eth-indexer' +import { rateInfoClient } from './rate-info-service' export const services = { lskIndexer, - ethIndexer + ethIndexer, + rate: rateInfoClient } diff --git a/src/lib/nodes/types.ts b/src/lib/nodes/types.ts index d938906fb..9fbe4c2c7 100644 --- a/src/lib/nodes/types.ts +++ b/src/lib/nodes/types.ts @@ -9,3 +9,8 @@ export type NodeType = 'adm' | 'eth' | 'btc' | 'doge' | 'dash' | 'lsk' export type NodeKind = 'node' | 'service' export type HealthcheckInterval = 'normal' | 'crucial' | 'onScreen' + +export type HealthcheckResult = { + height: number + ping: number +} diff --git a/src/locales/de.json b/src/locales/de.json index 24871f12a..0c338b1fa 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -124,7 +124,14 @@ "ms": "ms", "nodeLabelDescription": "Support decentralization and enhance privacy level—run your own ADAMANT node and web application for messaging. Node can be run following instructions. To add your nodes in the list for connection, you need to deploy web application on separate domain. This limitation refers to Content Security Policy (CSP). In iOS and Android applications there are no such limitations.", "offline": "Offline", - "ping": "Ping" + "ping": "Ping", + "service": "Service", + "socket": "Socket", + "tabs": { + "adm_nodes": "ADM Knooppunten", + "coin_nodes": "Munt Knooppunten", + "service_nodes": "Service Knooppunten" + } }, "notifications": { "message": { diff --git a/src/locales/en.json b/src/locales/en.json index 8924e9271..0228d65d6 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -163,10 +163,6 @@ "active": "Active", "fastest_title": "Choose the fastest node", "fastest_tooltip": "Requests will be processed with a fastest node", - "tabs": { - "adm_nodes": "ADM nodes", - "coin_nodes": "Coin nodes" - }, "label": "Type", "host": "Host", "inactive": "Inactive", @@ -176,7 +172,13 @@ "offline": "Offline", "coin": "Coin", "ping": "Ping", + "service": "Service", "socket": "Socket", + "tabs": { + "adm_nodes": "ADM nodes", + "coin_nodes": "Coin nodes", + "service_nodes": "Service nodes" + }, "unsupported": "Unsupported", "unsupported_reason_protocol": "HTTP is not allowed", "unsupported_reason_api_version": "Outdated API version", diff --git a/src/locales/ru.json b/src/locales/ru.json index 45720cbd9..aff5448f4 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -164,10 +164,6 @@ "active": "Активная", "fastest_title": "Подключаться к самому быстрому узлу", "fastest_tooltip": "Запросы будут обрабатываться самым быстрым узлом", - "tabs": { - "adm_nodes": "ADM ноды", - "coin_nodes": "Coin ноды" - }, "label": "Тип", "host": "Хост", "inactive": "Неактивная", @@ -177,7 +173,13 @@ "offline": "Недоступна", "coin": "Coin", "ping": "Пинг", + "service": "Сервис", "socket": "Сокеты", + "tabs": { + "adm_nodes": "ADM ноды", + "coin_nodes": "Coin ноды", + "service_nodes": "Сервис ноды" + }, "unsupported": "Не поддерживается", "unsupported_reason_protocol": "HTTP не поддерживается", "unsupported_reason_api_version": "API версия устарела", diff --git a/src/locales/zh.json b/src/locales/zh.json index 486b0760e..762d4f50d 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -163,10 +163,6 @@ "active": "活动", "fastest_title": "选择最快的节点", "fastest_tooltip": "将使用最快的节点处理请求", - "tabs": { - "adm_nodes": "ADM节点", - "coin_nodes": "硬币节点" - }, "label": "类型", "host": "主机", "inactive": "Inactive", @@ -176,7 +172,13 @@ "offline": "脱机", "coin": "硬币", "ping": "嗨", + "service": "服务", "socket": "套接字", + "tabs": { + "adm_nodes": "ADM节点", + "coin_nodes": "硬币节点", + "service_nodes": "服务节点" + }, "unsupported": "不受欢迎", "unsupported_reason_protocol": "不允许HTTP", "unsupported_reason_api_version": "API版本过期", diff --git a/src/store/index.js b/src/store/index.js index f830565da..88d7e2338 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -42,6 +42,8 @@ import cache from '@/store/cache' import rate from './modules/rate' import { cryptoTransferAsset, replyWithCryptoTransferAsset } from '@/lib/adamant-api/asset' import { PendingTxStore } from '@/lib/pending-transactions' +import servicesModule from './modules/services' +import servicesPlugin from './modules/services/services-plugin' export let interval @@ -245,6 +247,7 @@ const store = { identicon, notification, rate, + servicesModule, wallets: walletsModule // Wallets order and visibility } } @@ -261,7 +264,8 @@ registerVuexPlugins(storeInstance, [ navigatorOnline, socketsPlugin, botCommandsPlugin, - walletsPersistencePlugin + walletsPersistencePlugin, + servicesPlugin ]) export { store } // for tests diff --git a/src/store/modules/rate/index.js b/src/store/modules/rate/index.js deleted file mode 100644 index 13c85b7ed..000000000 --- a/src/store/modules/rate/index.js +++ /dev/null @@ -1,109 +0,0 @@ -import axios from 'axios' -import { getRandomServiceUrl } from '@/config/utils' - -const state = () => ({ - rates: {}, - isLoaded: false, - historyRates: {} -}) - -export let interval - -const UPDATE_RATES_INTERVAL = 90000 -const mutations = { - setRates(state, rates) { - state.rates = rates - }, - setHistoryRates(state, historyRates) { - state.historyRates[historyRates.name] = historyRates.value - }, - loadRates(state) { - state.isLoaded = true - } -} -const actions = { - getAllRates({ commit }) { - const url = getRandomServiceUrl('adm', 'infoService') - return new Promise((resolve, reject) => { - axios - .get(`${url}/get`) - .then((res) => { - const rates = res.data.result - commit('setRates', rates) - commit('loadRates') - resolve(res) - }) - .catch((err) => { - reject(err) - }) - }) - }, - getHistoryRates({ state, commit }, { timestamp }) { - if (!timestamp) return - const url = getRandomServiceUrl('adm', 'infoService') - if (state.historyRates[timestamp] !== undefined) { - return state.historyRates[timestamp] - } else { - return new Promise((resolve, reject) => { - axios - .get(`${url}/getHistory?timestamp=${timestamp}`) - .then((res) => { - const rates = res?.data?.result[0]?.tickers ?? null - commit('setHistoryRates', { name: timestamp, value: rates }) - resolve(res) - }) - .catch((err) => { - reject(err) - }) - }) - } - }, - startInterval: { - root: true, - handler({ dispatch }) { - function repeat() { - dispatch('getAllRates') - .catch((err) => console.error(err)) - .then(() => { - interval = setTimeout(repeat, UPDATE_RATES_INTERVAL) - }) - } - - repeat() - } - }, - stopInterval: { - root: true, - handler() { - clearTimeout(interval) - } - } -} -const getters = { - historyRate: (state, getters, rootState) => (timestamp, amount, crypto) => { - let historyRate - const currentCurrency = rootState.options.currentRate - const store = state.historyRates[timestamp] - if (store) { - historyRate = `${(store[`${crypto}/${currentCurrency}`] * amount).toFixed( - 2 - )} ${currentCurrency}` - } else { - historyRate = '�' - } - return historyRate - }, - rate: (state, getters, rootState) => (amount, crypto) => { - const currentCurrency = rootState.options.currentRate - const store = state.rates[`${crypto}/${currentCurrency}`] - const rate = store * amount - return isNaN(rate) ? '�' : `${rate.toFixed(2)} ${currentCurrency}` - } -} -export default { - state, - getters, - mutations, - actions, - namespaced: true -} diff --git a/src/store/modules/rate/index.ts b/src/store/modules/rate/index.ts new file mode 100644 index 000000000..732064b9b --- /dev/null +++ b/src/store/modules/rate/index.ts @@ -0,0 +1,17 @@ +import { Module } from 'vuex' +import { RootState } from '@/store/types' +import { RateState } from '@/store/modules/rate/types.ts' +import { state } from '@/store/modules/rate/rate-state.ts' +import { mutations } from '@/store/modules/rate/rate-mutations.ts' +import { actions } from '@/store/modules/rate/rate-actions.ts' +import { getters } from '@/store/modules/rate/rate-getters.ts' + +const rateModule: Module = { + namespaced: true, + state, + mutations, + actions, + getters +} + +export default rateModule diff --git a/src/store/modules/rate/rate-actions.ts b/src/store/modules/rate/rate-actions.ts new file mode 100644 index 000000000..004aa1db7 --- /dev/null +++ b/src/store/modules/rate/rate-actions.ts @@ -0,0 +1,68 @@ +import { ActionTree } from 'vuex' +import { RootState } from '@/store/types' +import rateInfoClient from '@/lib/nodes/rate-info-service' +import { RateState } from '@/store/modules/rate/types.ts' + +export let interval: NodeJS.Timeout + +const UPDATE_RATES_INTERVAL = 90000 + +export const actions: ActionTree = { + getAllRates({ commit }) { + return new Promise((resolve, reject) => { + rateInfoClient + .getAllRates() + .then(({ result, success }) => { + if (success) { + commit('setRates', result) + } + commit('loadRates') + resolve(result) + }) + .catch((err) => { + reject(err) + }) + }) + }, + getHistoryRates({ state, commit }, { timestamp }) { + if (!timestamp) return + if (state.historyRates[timestamp] !== undefined) { + return state.historyRates[timestamp] + } else { + return new Promise((resolve, reject) => { + rateInfoClient + .getHistory(timestamp) + .then(({ result, success }) => { + if (success) { + const rates = result[0]?.tickers ?? null + commit('setHistoryRates', { name: timestamp, value: rates }) + } + resolve(result) + }) + .catch((err) => { + reject(err) + }) + }) + } + }, + startInterval: { + root: true, + handler({ dispatch }) { + function repeat() { + dispatch('getAllRates') + .catch((err) => console.error(err)) + .then(() => { + interval = setTimeout(repeat, UPDATE_RATES_INTERVAL) + }) + } + + repeat() + } + }, + stopInterval: { + root: true, + handler() { + clearTimeout(interval) + } + } +} diff --git a/src/store/modules/rate/rate-getters.ts b/src/store/modules/rate/rate-getters.ts new file mode 100644 index 000000000..aad52b153 --- /dev/null +++ b/src/store/modules/rate/rate-getters.ts @@ -0,0 +1,26 @@ +import { GetterTree } from 'vuex' +import { RootState } from '@/store/types' +import { RateState } from '@/store/modules/rate/types.ts' + +export const getters: GetterTree = { + historyRate: + (state, getters, rootState) => (timestamp: number, amount: number, crypto: string) => { + let historyRate + const currentCurrency = rootState.options.currentRate + const store = state.historyRates[timestamp] + if (store) { + historyRate = `${(store[`${crypto}/${currentCurrency}`] * amount).toFixed( + 2 + )} ${currentCurrency}` + } else { + historyRate = '�' + } + return historyRate + }, + rate: (state, getters, rootState) => (amount: number, crypto: string) => { + const currentCurrency = rootState.options.currentRate + const store = state.rates[`${crypto}/${currentCurrency}`] + const rate = store * amount + return isNaN(rate) ? '�' : `${rate.toFixed(2)} ${currentCurrency}` + } +} diff --git a/src/store/modules/rate/rate-mutations.ts b/src/store/modules/rate/rate-mutations.ts new file mode 100644 index 000000000..6a1add41f --- /dev/null +++ b/src/store/modules/rate/rate-mutations.ts @@ -0,0 +1,14 @@ +import { MutationTree } from 'vuex' +import { Rates, RateState } from '@/store/modules/rate/types.ts' + +export const mutations: MutationTree = { + setRates(state, rates: Rates) { + state.rates = rates + }, + setHistoryRates(state, historyRates: { name: number; value: Rates }) { + state.historyRates[historyRates.name] = historyRates.value + }, + loadRates(state) { + state.isLoaded = true + } +} diff --git a/src/store/modules/rate/rate-state.ts b/src/store/modules/rate/rate-state.ts new file mode 100644 index 000000000..be557dd70 --- /dev/null +++ b/src/store/modules/rate/rate-state.ts @@ -0,0 +1,7 @@ +import { RateState } from '@/store/modules/rate/types.ts' + +export const state: RateState = { + rates: {}, + isLoaded: false, + historyRates: {} +} diff --git a/src/store/modules/rate/types.ts b/src/store/modules/rate/types.ts new file mode 100644 index 000000000..4b86448eb --- /dev/null +++ b/src/store/modules/rate/types.ts @@ -0,0 +1,6 @@ +export type Rates = Record +export type RateState = { + rates: Rates + isLoaded: boolean + historyRates: Record +} diff --git a/src/store/modules/services/index.ts b/src/store/modules/services/index.ts new file mode 100644 index 000000000..10c8741e8 --- /dev/null +++ b/src/store/modules/services/index.ts @@ -0,0 +1,17 @@ +import { state } from './services-state.ts' +import { actions } from './services-actions.ts' +import { mutations } from './services-mutations.ts' +import { getters } from './services-getters.ts' +import { Module } from 'vuex' +import { RootState } from '@/store/types' +import { ServicesState } from '@/store/modules/services/types.ts' + +const servicesModule: Module = { + namespaced: true, + state, + actions, + mutations, + getters +} + +export default servicesModule diff --git a/src/store/modules/services/services-actions.ts b/src/store/modules/services/services-actions.ts new file mode 100644 index 000000000..9995cfe62 --- /dev/null +++ b/src/store/modules/services/services-actions.ts @@ -0,0 +1,20 @@ +import { services } from '@/lib/nodes/services' +import { ActionTree } from 'vuex' +import { RootState } from '@/store/types' +import { ServicesState } from '@/store/modules/services/types.ts' + +export const actions: ActionTree = { + updateStatus() { + for (const [, client] of Object.entries(services)) { + client.checkHealth() + } + }, + + toggle(context, payload) { + context.commit('toggle', payload) + }, + + useFastestService(context, payload) { + context.commit('useFastestService', payload) + } +} diff --git a/src/store/modules/services/services-getters.ts b/src/store/modules/services/services-getters.ts new file mode 100644 index 000000000..214287a09 --- /dev/null +++ b/src/store/modules/services/services-getters.ts @@ -0,0 +1,12 @@ +import { GetterTree } from 'vuex' +import { RootState } from '@/store/types' +import { ServicesState } from '@/store/modules/services/types.ts' + +export const getters: GetterTree = { + rate(state) { + return Object.values(state.rate) + }, + services(state, getters) { + return [...getters.rate] + } +} diff --git a/src/store/modules/services/services-mutations.ts b/src/store/modules/services/services-mutations.ts new file mode 100644 index 000000000..563ad6fe3 --- /dev/null +++ b/src/store/modules/services/services-mutations.ts @@ -0,0 +1,31 @@ +import { MutationTree } from 'vuex' +import { AvailableService, ServicesState } from '@/store/modules/services/types.ts' + +export const mutations: MutationTree = { + useFastestService(state, value) { + state.useFastestService = value + }, + + toggle(state, payload: { type: AvailableService; url: string; active: boolean }) { + if (!state[payload.type]) { + state[payload.type] = {} + } + const node = state[payload.type][payload.url] + if (node) { + node.active = payload.active + } + }, + + status( + state, + { + status, + serviceType + }: { serviceType: AvailableService; status: { url: string; active: boolean } } + ) { + if (!state[serviceType]) { + state[serviceType] = {} + } + state[serviceType][status.url] = status + } +} diff --git a/src/store/modules/services/services-plugin.ts b/src/store/modules/services/services-plugin.ts new file mode 100644 index 000000000..22fa5e7b0 --- /dev/null +++ b/src/store/modules/services/services-plugin.ts @@ -0,0 +1,33 @@ +import { services } from '@/lib/nodes/services' +import { Store } from 'vuex' +import { AvailableService, ServicesState } from '@/store/modules/services/types.ts' + +export default (store: Store) => { + for (const [serviceType, client] of Object.entries(services)) { + client + .getNodes() + .forEach((status) => store.commit('servicesModule/status', { status, serviceType })) + + client.onStatusUpdate((status) => { + store.commit('servicesModule/status', { status, serviceType }) + }) + } + store.commit('servicesModule/useFastestService', services.rate.useFastest) + + store.subscribe((mutation) => { + const { type, payload } = mutation + + if (type === 'servicesModule/useFastestService') { + services.rate.setUseFastest(!!payload) + } + + if (type === 'servicesModule/toggle') { + const selectedNodeType = payload.type as AvailableService + const newStatus = services[selectedNodeType].toggleNode(payload.url, payload.active) + + if (newStatus) { + store.commit('servicesModule/status', { status: newStatus, serviceType: selectedNodeType }) + } + } + }) +} diff --git a/src/store/modules/services/services-state.ts b/src/store/modules/services/services-state.ts new file mode 100644 index 000000000..9a78028f5 --- /dev/null +++ b/src/store/modules/services/services-state.ts @@ -0,0 +1,6 @@ +import { ServicesState } from '@/store/modules/services/types.ts' + +export const state: ServicesState = { + rate: {}, + useFastestService: true +} diff --git a/src/store/modules/services/types.ts b/src/store/modules/services/types.ts new file mode 100644 index 000000000..817ef8909 --- /dev/null +++ b/src/store/modules/services/types.ts @@ -0,0 +1,6 @@ +export type ServicesState = { + rate: Record + useFastestService: true +} + +export type AvailableService = 'rates-info' From 833e831f531831958d09b95a9f2563341ee083d5 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 29 May 2024 21:27:08 +0300 Subject: [PATCH 015/218] fix: toggle active --- src/lib/nodes/constants.ts | 4 ++-- src/lib/nodes/rate-info-service/RateInfoService.ts | 2 +- src/store/modules/services/types.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/nodes/constants.ts b/src/lib/nodes/constants.ts index 6cd0ddee3..78824cc72 100644 --- a/src/lib/nodes/constants.ts +++ b/src/lib/nodes/constants.ts @@ -9,7 +9,7 @@ export type TNodeLabel = | 'dash-node' | 'lsk-node' | 'lsk-indexer' - | 'rates-info' + | 'rate' type KebabToCamelCase = S extends `${infer T}-${infer U}` ? `${T}${Capitalize>}` @@ -38,5 +38,5 @@ export const NODE_LABELS: NodeLabels = { DashNode: 'dash-node', LskNode: 'lsk-node', LskIndexer: 'lsk-indexer', - RatesInfo: 'rates-info' + Rate: 'rate' } diff --git a/src/lib/nodes/rate-info-service/RateInfoService.ts b/src/lib/nodes/rate-info-service/RateInfoService.ts index 0cd90a8e8..e1931296f 100644 --- a/src/lib/nodes/rate-info-service/RateInfoService.ts +++ b/src/lib/nodes/rate-info-service/RateInfoService.ts @@ -21,7 +21,7 @@ export type RateHistoryInfoResponse = { export class RateInfoService extends Node { constructor(url: string) { - super(url, 'adm', 'service', NODE_LABELS.RatesInfo) + super(url, 'adm', 'service', NODE_LABELS.Rate) } protected buildClient(): AxiosInstance { return axios.create({ diff --git a/src/store/modules/services/types.ts b/src/store/modules/services/types.ts index 817ef8909..ead3e9a79 100644 --- a/src/store/modules/services/types.ts +++ b/src/store/modules/services/types.ts @@ -3,4 +3,4 @@ export type ServicesState = { useFastestService: true } -export type AvailableService = 'rates-info' +export type AvailableService = 'rate' From ca18b529fec491b94f12b18c156d6b991b850378 Mon Sep 17 00:00:00 2001 From: PaulDremanovich Date: Tue, 4 Jun 2024 19:59:47 +0400 Subject: [PATCH 016/218] fix: ui NodeOfflineDialog --- src/components/NodesOfflineDialog.vue | 63 ++++++++++++++++++++++----- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/src/components/NodesOfflineDialog.vue b/src/components/NodesOfflineDialog.vue index b8e47f566..5dd60bbbb 100644 --- a/src/components/NodesOfflineDialog.vue +++ b/src/components/NodesOfflineDialog.vue @@ -1,5 +1,5 @@ @@ -49,6 +58,7 @@ export default { const nodes = computed(() => store.getters['nodes/adm']) const isOnline = computed(() => store.getters['isOnline']) + const className = 'nodes-offline-dialog' const offlineNodesStatus = computed(() => { return { @@ -82,8 +92,41 @@ export default { nodes, classes, offlineNodesStatus, - showDialog + showDialog, + className } } } + From e6f07874e502563e3d9d6585b108ad20dd5259e4 Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 5 Jun 2024 21:12:32 +0100 Subject: [PATCH 017/218] feat(useChatName): add `fallbackToAddress` param --- src/components/AChat/hooks/useChatName.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/components/AChat/hooks/useChatName.ts b/src/components/AChat/hooks/useChatName.ts index 6e3045b77..1283a1c89 100644 --- a/src/components/AChat/hooks/useChatName.ts +++ b/src/components/AChat/hooks/useChatName.ts @@ -4,7 +4,14 @@ import { useStore } from 'vuex' import { isAdamantChat } from '@/lib/chat/meta/utils' -export function useChatName(address: MaybeRef) { +/** + * Returns the chat name of the partner. + * If no name is assigned, returns an empty string. + * + * @param address - The address of the partner. + * @param fallbackToAddress - If true, fallback to address if no name was assigned. + */ +export function useChatName(address: MaybeRef, fallbackToAddress = false) { const store = useStore() const { t } = useI18n() @@ -15,7 +22,17 @@ export function useChatName(address: MaybeRef) { }) const name = computed(() => { - return isAdamantChat(address) ? t(chatName.value) : chatName.value + const addressValue = unref(address) + + if (isAdamantChat(addressValue)) { + return t(chatName.value) + } + + if (fallbackToAddress) { + return chatName.value || addressValue + } + + return chatName.value }) return name From 909ffc0fd555f9dcbd276b1039b55ae639685546 Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 5 Jun 2024 21:13:43 +0100 Subject: [PATCH 018/218] refactor(ChatPreview): rewrite to Composition API --- src/components/ChatPreview.vue | 205 +++++++++++++++++---------------- 1 file changed, 107 insertions(+), 98 deletions(-) diff --git a/src/components/ChatPreview.vue b/src/components/ChatPreview.vue index be4496d3d..3067b3dc3 100644 --- a/src/components/ChatPreview.vue +++ b/src/components/ChatPreview.vue @@ -33,7 +33,7 @@ 'a-text-regular-enlarged-bold': true, [`${className}__title`]: true }" - >{{ isAdamantChat(contactId) ? $t(contactName) : contactName }}{{ chatName }}

{{ formatDate(createdAt) }} @@ -83,33 +83,42 @@ - diff --git a/src/components/transactions/TransactionListItem.vue b/src/components/transactions/TransactionListItem.vue new file mode 100644 index 000000000..e465bd358 --- /dev/null +++ b/src/components/transactions/TransactionListItem.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/components/transactions/TransactionTemplate.vue b/src/components/transactions/TransactionTemplate.vue deleted file mode 100644 index f342cb22f..000000000 --- a/src/components/transactions/TransactionTemplate.vue +++ /dev/null @@ -1,492 +0,0 @@ - - - - - diff --git a/src/components/transactions/TransactionTemplateLoading.vue b/src/components/transactions/TransactionTemplateLoading.vue deleted file mode 100644 index 2abafd09a..000000000 --- a/src/components/transactions/TransactionTemplateLoading.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/src/hooks/address/useFindAdmAddress.ts b/src/components/transactions/hooks/useFindAdmAddress.ts similarity index 100% rename from src/hooks/address/useFindAdmAddress.ts rename to src/components/transactions/hooks/useFindAdmAddress.ts diff --git a/src/hooks/address/useFindAdmTransaction.ts b/src/components/transactions/hooks/useFindAdmTransaction.ts similarity index 54% rename from src/hooks/address/useFindAdmTransaction.ts rename to src/components/transactions/hooks/useFindAdmTransaction.ts index 2b512e0be..7fa0073f7 100644 --- a/src/hooks/address/useFindAdmTransaction.ts +++ b/src/components/transactions/hooks/useFindAdmTransaction.ts @@ -1,27 +1,30 @@ -import { computed, MaybeRef, unref } from 'vue' +import { computed, ComputedRef, MaybeRef, unref } from 'vue' import { useStore } from 'vuex' +import { NormalizedChatMessageTransaction } from '@/lib/chat/helpers' /** * Find ADM special message by transactionHash in the chat messages */ -export function useFindAdmTransaction(hash: MaybeRef) { +export function useFindAdmTransaction( + hash: MaybeRef +): ComputedRef { const store = useStore() return computed(() => { const hashValue = unref(hash) - const admTx = {} as any + let admTx: NormalizedChatMessageTransaction | null = null as any // Bad news, everyone: we'll have to scan the messages Object.values(store.state.chat.chats).some((chat) => { // @ts-expect-error-next-line Object.values(chat.messages).some((msg) => { // @ts-expect-error-next-line if (msg.hash && msg.hash === hashValue) { - Object.assign(admTx, msg) + admTx = msg as NormalizedChatMessageTransaction } - return !!admTx.id + return !!admTx?.id }) - return !!admTx.id + return !!admTx?.id }) return admTx }) diff --git a/src/components/transactions/utils/getPartnerAddress.ts b/src/components/transactions/utils/getPartnerAddress.ts new file mode 100644 index 000000000..3d6d0671a --- /dev/null +++ b/src/components/transactions/utils/getPartnerAddress.ts @@ -0,0 +1,6 @@ +/** + * Get the partner address based on the sender and recipient addresses. + */ +export function getPartnerAddress(senderId: string, recipientId: string, mineAddress: string) { + return senderId === mineAddress ? recipientId : senderId +} diff --git a/src/lib/formatters.js b/src/lib/formatters.js index 201a91c89..85863a8ab 100644 --- a/src/lib/formatters.js +++ b/src/lib/formatters.js @@ -18,7 +18,7 @@ function getTime(date) { return time } -function formatDate(timestamp) { +export function formatDate(timestamp) { timestamp = parseInt(timestamp) // That's for the ADM timestamps, which use EPOCH as a base. // Other cryptos use normal timestamps From 70503a25844eacf8c5c4ba0824bcf39f1cb33048 Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 13 Jul 2024 20:44:53 +0100 Subject: [PATCH 068/218] fix(nodes/storage): access of undefined value when switching from an older app version --- src/lib/nodes/storage.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/lib/nodes/storage.ts b/src/lib/nodes/storage.ts index 9b7da1659..dd59e2b14 100644 --- a/src/lib/nodes/storage.ts +++ b/src/lib/nodes/storage.ts @@ -55,15 +55,21 @@ export const nodesStorage = { getUseFastest(node: NodeType, kind: NodeKind = 'node') { const options = optionsStorage.getItem() - return !!options[node][kind]?.useFastest + return !!options[node]?.[kind]?.useFastest }, setUseFastest(value: boolean, node: NodeType, kind: NodeKind = 'node') { const options = optionsStorage.getItem() if (!options[node]) { - options[node] = { node: { useFastest: false } } - options[node][kind] = { useFastest: value } + options[node] = { + node: { useFastest: false }, + service: { useFastest: true } + } } + if (!options[node][kind]) { + options[node][kind] = { useFastest: false } + } + options[node][kind] = { useFastest: value } optionsStorage.setItem(options) From 8c9bf26bdc9cd64e57c50028d4fc20a3f76cf98f Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 13 Jul 2024 20:50:00 +0100 Subject: [PATCH 069/218] refactor(nodes/storage): reuse code --- src/lib/nodes/storage.ts | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/lib/nodes/storage.ts b/src/lib/nodes/storage.ts index dd59e2b14..f6703ff03 100644 --- a/src/lib/nodes/storage.ts +++ b/src/lib/nodes/storage.ts @@ -8,12 +8,8 @@ type State = Record type Options = Record< NodeType, { - node: { - useFastest: boolean - } - service?: { - useFastest: boolean - } + node: { useFastest: boolean } + service: { useFastest: boolean } } > @@ -22,16 +18,17 @@ const NODES_OPTIONS_STORAGE_KEY = 'NODES_OPTIONS_STORAGE' // for storing common const stateStorage = new TypedStorage(NODES_STATE_STORAGE_KEY, {} as State, window.localStorage) +const defaultConfig = { + node: { useFastest: false }, + service: { useFastest: false } +} const defaultOptions: Options = { - adm: { - node: { useFastest: false }, - service: { useFastest: true } - }, - btc: { node: { useFastest: false } }, - doge: { node: { useFastest: false } }, - dash: { node: { useFastest: false } }, - eth: { node: { useFastest: false } }, - kly: { node: { useFastest: false }, service: { useFastest: true } } + adm: defaultConfig, + btc: defaultConfig, + doge: defaultConfig, + dash: defaultConfig, + eth: defaultConfig, + kly: defaultConfig } const optionsStorage = new TypedStorage( From f7f3e61cb02d566613973c3b38bc74863fbd9b61 Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 13 Jul 2024 21:09:43 +0100 Subject: [PATCH 070/218] fix(nodes/storage): modify only `useFastest` option --- src/lib/nodes/storage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/nodes/storage.ts b/src/lib/nodes/storage.ts index f6703ff03..a4650b372 100644 --- a/src/lib/nodes/storage.ts +++ b/src/lib/nodes/storage.ts @@ -67,7 +67,7 @@ export const nodesStorage = { options[node][kind] = { useFastest: false } } - options[node][kind] = { useFastest: value } + options[node][kind].useFastest = value optionsStorage.setItem(options) } From 21e6312707e33d62f1970c5ec57156e0bfdbb425 Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 13 Jul 2024 21:11:29 +0100 Subject: [PATCH 071/218] refactor(NodesTable): move Service Nodes tab to the end --- src/components/nodes/NodesTable.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/nodes/NodesTable.vue b/src/components/nodes/NodesTable.vue index 674180fc4..023f10795 100644 --- a/src/components/nodes/NodesTable.vue +++ b/src/components/nodes/NodesTable.vue @@ -2,20 +2,20 @@
{{ $t('nodes.tabs.adm_nodes') }} - {{ $t('nodes.tabs.service_nodes') }} {{ $t('nodes.tabs.coin_nodes') }} + {{ $t('nodes.tabs.service_nodes') }} - - - + + +
From a6d15f2d6526a1c63281a97b0882bb64dc41b19e Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 13 Jul 2024 21:14:14 +0100 Subject: [PATCH 072/218] refactor(NodesTable): shorter import --- src/components/nodes/NodesTable.vue | 2 +- src/components/nodes/services/index.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 src/components/nodes/services/index.ts diff --git a/src/components/nodes/NodesTable.vue b/src/components/nodes/NodesTable.vue index 023f10795..4bb72e87d 100644 --- a/src/components/nodes/NodesTable.vue +++ b/src/components/nodes/NodesTable.vue @@ -88,8 +88,8 @@ import { defineComponent, ref, computed } from 'vue' import { AdmNodesTable } from './adm' import { CoinNodesTable } from './coins' +import { ServiceNodesTable } from './services' import { useStore } from 'vuex' -import ServiceNodesTable from './services/ServiceNodesTable.vue' const className = 'nodes-table' const classes = { diff --git a/src/components/nodes/services/index.ts b/src/components/nodes/services/index.ts new file mode 100644 index 000000000..11e240fee --- /dev/null +++ b/src/components/nodes/services/index.ts @@ -0,0 +1 @@ +export { default as ServiceNodesTable } from './ServiceNodesTable.vue' From ec9c9622e9da3e1325aeb11095e50c17633c008b Mon Sep 17 00:00:00 2001 From: bludnic Date: Sat, 13 Jul 2024 21:14:40 +0100 Subject: [PATCH 073/218] refactor(NodesTable): move npm packages imports at the top --- src/components/nodes/NodesTable.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/nodes/NodesTable.vue b/src/components/nodes/NodesTable.vue index 4bb72e87d..ac6fa1eb2 100644 --- a/src/components/nodes/NodesTable.vue +++ b/src/components/nodes/NodesTable.vue @@ -86,10 +86,11 @@ diff --git a/src/components/transactions/DogeTransaction.vue b/src/components/transactions/DogeTransaction.vue deleted file mode 100644 index 665c0b18b..000000000 --- a/src/components/transactions/DogeTransaction.vue +++ /dev/null @@ -1,102 +0,0 @@ - - - diff --git a/src/views/transactions/Transaction.vue b/src/views/transactions/Transaction.vue index 6a2a19ec7..a8ce6bebc 100644 --- a/src/views/transactions/Transaction.vue +++ b/src/views/transactions/Transaction.vue @@ -7,11 +7,9 @@ import AdmTransaction from '../../components/transactions/AdmTransaction.vue' import EthTransaction from '../../components/transactions/EthTransaction.vue' import Erc20Transaction from '../../components/transactions/Erc20Transaction.vue' import BtcTransaction from '../../components/transactions/BtcTransaction.vue' -import DogeTransaction from '../../components/transactions/DogeTransaction.vue' -import DashTransaction from '../../components/transactions/DashTransaction.vue' import KlyTransaction from '../../components/transactions/KlyTransaction.vue' -import { Cryptos, isErc20, isKlyBased } from '../../lib/constants' +import { Cryptos, isErc20, isBtcBased, isKlyBased } from '../../lib/constants' import { getTxUpdateInterval } from '../../lib/transactionsFetching' export default { @@ -21,8 +19,6 @@ export default { EthTransaction, Erc20Transaction, BtcTransaction, - DogeTransaction, - DashTransaction, KlyTransaction }, props: { @@ -43,9 +39,7 @@ export default { computed: { transactionComponent() { if (this.crypto === Cryptos.ETH) return 'eth-transaction' - if (this.crypto === Cryptos.BTC) return 'btc-transaction' - if (this.crypto === Cryptos.DOGE) return 'doge-transaction' - if (this.crypto === Cryptos.DASH) return 'dash-transaction' + if (isBtcBased(this.crypto)) return 'btc-transaction' if (isErc20(this.crypto)) return 'erc20-transaction' if (isKlyBased(this.crypto)) return 'kly-transaction' return 'adm-transaction' From 04a91daf88b5276d08a84d6d716543eabaef3b4a Mon Sep 17 00:00:00 2001 From: bludnic Date: Mon, 15 Jul 2024 16:45:32 +0100 Subject: [PATCH 091/218] fix(useFindAdmTransaction): fix type --- src/components/transactions/Transaction.vue | 3 ++- src/components/transactions/hooks/useFindAdmTransaction.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/transactions/Transaction.vue b/src/components/transactions/Transaction.vue index 9a9841dab..0a037ac84 100644 --- a/src/components/transactions/Transaction.vue +++ b/src/components/transactions/Transaction.vue @@ -151,6 +151,7 @@ import { TransactionStatusType, tsUpdatable } from '@/lib/constants' +import { NormalizedChatMessageTransaction } from '@/lib/chat/helpers' import { InconsistentStatus } from './utils/getInconsistentStatus' import { AnyCoinTransaction } from '@/lib/nodes/types/transaction' import AppToolbarCentered from '@/components/AppToolbarCentered.vue' @@ -184,7 +185,7 @@ export default defineComponent({ type: String }, admTx: { - type: Object + type: Object as PropType }, fetchStatus: { type: String as PropType, diff --git a/src/components/transactions/hooks/useFindAdmTransaction.ts b/src/components/transactions/hooks/useFindAdmTransaction.ts index 7fa0073f7..f32c44411 100644 --- a/src/components/transactions/hooks/useFindAdmTransaction.ts +++ b/src/components/transactions/hooks/useFindAdmTransaction.ts @@ -7,13 +7,13 @@ import { NormalizedChatMessageTransaction } from '@/lib/chat/helpers' */ export function useFindAdmTransaction( hash: MaybeRef -): ComputedRef { +): ComputedRef { const store = useStore() return computed(() => { const hashValue = unref(hash) - let admTx: NormalizedChatMessageTransaction | null = null as any + let admTx: NormalizedChatMessageTransaction | undefined // Bad news, everyone: we'll have to scan the messages Object.values(store.state.chat.chats).some((chat) => { // @ts-expect-error-next-line From 00892f3943be8f9f9af124ffd8f9bf6e870aaba9 Mon Sep 17 00:00:00 2001 From: bludnic Date: Mon, 15 Jul 2024 17:19:26 +0100 Subject: [PATCH 092/218] fix(Transaction): use PascalCale to support TS --- src/components/transactions/AdmTransaction.vue | 2 +- src/components/transactions/BtcTransaction.vue | 2 +- src/components/transactions/Erc20Transaction.vue | 2 +- src/components/transactions/EthTransaction.vue | 2 +- src/components/transactions/KlyTransaction.vue | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/transactions/AdmTransaction.vue b/src/components/transactions/AdmTransaction.vue index 911c059a2..44a649172 100644 --- a/src/components/transactions/AdmTransaction.vue +++ b/src/components/transactions/AdmTransaction.vue @@ -1,5 +1,5 @@ From 1a27595a1b6044cddef3ba893433a998e0498a97 Mon Sep 17 00:00:00 2001 From: bludnic Date: Tue, 16 Jul 2024 00:08:12 +0100 Subject: [PATCH 104/218] feat(useTransactionQuery): unify into a single hook --- src/hooks/queries/transaction/index.ts | 1 + .../transaction/useTransactionQuery.ts | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 src/hooks/queries/transaction/useTransactionQuery.ts diff --git a/src/hooks/queries/transaction/index.ts b/src/hooks/queries/transaction/index.ts index 3d2e3bce2..ca25fdd96 100644 --- a/src/hooks/queries/transaction/index.ts +++ b/src/hooks/queries/transaction/index.ts @@ -5,3 +5,4 @@ export { useDashTransactionQuery } from './useDashTransactionQuery' export { useEthTransactionQuery } from './useEthTransactionQuery' export { useErc20TransactionQuery } from './useErc20TransactionQuery' export { useKlyTransactionQuery } from './useKlyTransactionQuery' +export { useTransactionQuery } from './useTransactionQuery' diff --git a/src/hooks/queries/transaction/useTransactionQuery.ts b/src/hooks/queries/transaction/useTransactionQuery.ts new file mode 100644 index 000000000..2917c7067 --- /dev/null +++ b/src/hooks/queries/transaction/useTransactionQuery.ts @@ -0,0 +1,36 @@ +import { MaybeRef } from 'vue' +import { CryptoSymbol, isErc20 } from '@/lib/constants' +import { useAdmTransactionQuery } from './useAdmTransactionQuery' +import { useBtcTransactionQuery } from './useBtcTransactionQuery' +import { useDogeTransactionQuery } from './useDogeTransactionQuery' +import { useDashTransactionQuery } from './useDashTransactionQuery' +import { useEthTransactionQuery } from './useEthTransactionQuery' +import { useErc20TransactionQuery } from './useErc20TransactionQuery' +import { useKlyTransactionQuery } from './useKlyTransactionQuery' + +const query = { + ADM: useAdmTransactionQuery, + BTC: useBtcTransactionQuery, + DOGE: useDogeTransactionQuery, + DASH: useDashTransactionQuery, + ETH: useEthTransactionQuery, + KLY: useKlyTransactionQuery +} as const + +export function useTransactionQuery(transactionId: MaybeRef, crypto: CryptoSymbol) { + if (isErc20(crypto)) { + return useErc20TransactionQuery(crypto)(transactionId) + } + + switch (crypto) { + case 'ADM': + case 'BTC': + case 'DOGE': + case 'DASH': + case 'ETH': + case 'KLY': + return query[crypto](transactionId) + default: + throw new Error(`Unsupported crypto: ${crypto}`) + } +} From 1990e2dff4a0be4751afb185bafd56e9d93fb50a Mon Sep 17 00:00:00 2001 From: PaulDremanovich Date: Tue, 16 Jul 2024 20:52:45 +0300 Subject: [PATCH 105/218] fix: healthcheck for DogeNode. Refactoring --- src/lib/nodes/doge/DogeNode.ts | 28 +++++++++++++------ .../modules/services/services-actions.ts | 6 ++-- .../modules/services/services-mutations.ts | 7 ++--- src/store/modules/services/services-plugin.ts | 6 ++-- src/store/modules/services/types.ts | 12 +++++++- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/lib/nodes/doge/DogeNode.ts b/src/lib/nodes/doge/DogeNode.ts index f9dcf6bc0..dd71043cf 100644 --- a/src/lib/nodes/doge/DogeNode.ts +++ b/src/lib/nodes/doge/DogeNode.ts @@ -4,8 +4,9 @@ import { Node } from '@/lib/nodes/abstract.node' import { NODE_LABELS } from '@/lib/nodes/constants' import { formatDogeVersion } from '@/lib/nodes/utils/nodeVersionFormatters' -type FetchBtcNodeInfoResult = { - info: { +type FetchDogeNodeInfoResult = { + error: string + result: { version: number } } @@ -25,19 +26,30 @@ export class DogeNode extends Node { protected async checkHealth() { const time = Date.now() - const height = await this.client - .get('/api/blocks?limit=0') - .then((res) => res.data.blocks[0].height) + + const { data } = await this.client.post('/', { + jsonrpc: '1.0', + id: 'adm', + method: 'getblockchaininfo', + params: [] + }) + + const { blocks } = data.result return { - height, + height: Number(blocks), ping: Date.now() - time } } protected async fetchNodeVersion(): Promise { - const { data } = await this.client.get('/api/status') - const { version } = data.info + const { data } = await this.client.post('/', { + jsonrpc: '1.0', + id: 'adm', + method: 'getnetworkinfo', + params: [] + }) + const { version } = data.result if (version) { this.version = formatDogeVersion(version) } diff --git a/src/store/modules/services/services-actions.ts b/src/store/modules/services/services-actions.ts index e259fc2d3..451856933 100644 --- a/src/store/modules/services/services-actions.ts +++ b/src/store/modules/services/services-actions.ts @@ -1,7 +1,7 @@ import { services } from '@/lib/nodes/services' import { ActionTree } from 'vuex' import { RootState } from '@/store/types' -import { ServicesState } from '@/store/modules/services/types' +import { ServicesState, TogglePayload } from '@/store/modules/services/types' export const actions: ActionTree = { updateStatus() { @@ -10,11 +10,11 @@ export const actions: ActionTree = { } }, - toggle(context, payload) { + toggle(context, payload: TogglePayload) { context.commit('toggle', payload) }, - useFastestService(context, payload) { + useFastestService(context, payload: boolean) { context.commit('useFastestService', payload) } } diff --git a/src/store/modules/services/services-mutations.ts b/src/store/modules/services/services-mutations.ts index dd3da3d05..79d01a1a8 100644 --- a/src/store/modules/services/services-mutations.ts +++ b/src/store/modules/services/services-mutations.ts @@ -1,11 +1,8 @@ import { MutationTree } from 'vuex' -import { AvailableService, ServicesState } from '@/store/modules/services/types' - -type StatusPayload = { serviceType: AvailableService; status: { url: string; active: boolean } } -type TogglePayload = { type: AvailableService; url: string; active: boolean } +import { ServicesState, StatusPayload, TogglePayload } from '@/store/modules/services/types' export const mutations: MutationTree = { - useFastestService(state, value) { + useFastestService(state, value: boolean) { state.useFastestService = value }, diff --git a/src/store/modules/services/services-plugin.ts b/src/store/modules/services/services-plugin.ts index 53986119a..2bd281907 100644 --- a/src/store/modules/services/services-plugin.ts +++ b/src/store/modules/services/services-plugin.ts @@ -1,9 +1,9 @@ import { services } from '@/lib/nodes/services' -import { Store } from 'vuex' +import { Plugin } from 'vuex' import { AvailableService, ServicesState } from '@/store/modules/services/types' import { NODE_LABELS } from '@/lib/nodes/constants' -export default (store: Store) => { +const servicesPlugin: Plugin = (store) => { for (const [serviceType, client] of Object.entries(services)) { client.getNodes().forEach((status) => store.commit('services/status', { status, serviceType })) @@ -30,3 +30,5 @@ export default (store: Store) => { } }) } + +export default servicesPlugin diff --git a/src/store/modules/services/types.ts b/src/store/modules/services/types.ts index c67658cd8..3d8e32deb 100644 --- a/src/store/modules/services/types.ts +++ b/src/store/modules/services/types.ts @@ -2,7 +2,17 @@ import { NODE_LABELS } from '@/lib/nodes/constants' export type ServicesState = { [NODE_LABELS.RatesInfo]: Record - useFastestService: true + useFastestService: boolean } export type AvailableService = 'rates-info' + +export type StatusPayload = { + serviceType: AvailableService + status: { url: string; active: boolean } +} +export type TogglePayload = { type: AvailableService; url: string; active: boolean } + +export type ServicesGetters = { + rate: (state: ServicesState) => { active: boolean }[] +} From da7fabacb4f5a420b3c0515f4b9ec6736711f19b Mon Sep 17 00:00:00 2001 From: PaulDremanovich Date: Wed, 17 Jul 2024 00:37:23 +0300 Subject: [PATCH 106/218] feat: added btcIndexer, dogeIndexer, ethIndexer, klyIndexer in settings on services tab --- src/lib/nodes/abstract.node.ts | 1 + src/lib/nodes/nodes-manager.ts | 4 ++++ src/lib/nodes/services.ts | 10 +++++++--- src/lib/nodes/utils/getHealthcheckConfig.ts | 3 +-- .../modules/services/services-getters.ts | 20 ++++++++++++++++++- src/store/modules/services/services-state.ts | 4 ++++ src/store/modules/services/types.ts | 15 +++++++++----- 7 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/lib/nodes/abstract.node.ts b/src/lib/nodes/abstract.node.ts index 0b003b8d0..1a0ce5f5d 100644 --- a/src/lib/nodes/abstract.node.ts +++ b/src/lib/nodes/abstract.node.ts @@ -154,6 +154,7 @@ export abstract class Node { updateHealthCheckInterval(interval: HealthcheckInterval) { this.healthCheckInterval = interval + this.startHealthcheck().catch(console.error) } private fireStatusChange() { diff --git a/src/lib/nodes/nodes-manager.ts b/src/lib/nodes/nodes-manager.ts index 8d6abcdfe..d99818278 100644 --- a/src/lib/nodes/nodes-manager.ts +++ b/src/lib/nodes/nodes-manager.ts @@ -1,11 +1,15 @@ import type { HealthcheckInterval } from './types' import { nodes } from './nodes' +import { services } from './services' class NodesManager { updateHealthcheckInterval(interval: HealthcheckInterval) { for (const node of Object.values(nodes)) { node.updateHealthCheckInterval(interval) } + for (const service of Object.values(services)) { + service.updateHealthCheckInterval(interval) + } } } diff --git a/src/lib/nodes/services.ts b/src/lib/nodes/services.ts index 03b8a0d95..e369a5d7d 100644 --- a/src/lib/nodes/services.ts +++ b/src/lib/nodes/services.ts @@ -1,10 +1,14 @@ import { klyIndexer } from './kly-indexer' import { ethIndexer } from './eth-indexer' import { rateInfoClient } from './rate-info-service' -import { NODE_LABELS } from '@/lib/nodes/constants.ts' +import { NODE_LABELS } from '@/lib/nodes/constants' +import { dogeIndexer } from './doge-indexer' +import { btcIndexer } from './btc-indexer' export const services = { - klyIndexer, - ethIndexer, + [NODE_LABELS.KlyIndexer]: klyIndexer, + [NODE_LABELS.EthIndexer]: ethIndexer, + [NODE_LABELS.BtcIndexer]: btcIndexer, + [NODE_LABELS.DogeIndexer]: dogeIndexer, [NODE_LABELS.RatesInfo]: rateInfoClient } diff --git a/src/lib/nodes/utils/getHealthcheckConfig.ts b/src/lib/nodes/utils/getHealthcheckConfig.ts index c399ea180..84d8b59f1 100644 --- a/src/lib/nodes/utils/getHealthcheckConfig.ts +++ b/src/lib/nodes/utils/getHealthcheckConfig.ts @@ -7,10 +7,9 @@ export function getNodeHealthcheckConfig(nodeType: NodeType): NodeHealthcheck { } export function getServiceHealthcheckConfig(nodeType: NodeType): ServiceHealthcheck { - if (nodeType === 'eth') { + if (!config[nodeType].services) { return config[nodeType].nodes.healthCheck // Workaround: there no configuration for ETH services } - return config[nodeType].services.healthCheck } diff --git a/src/store/modules/services/services-getters.ts b/src/store/modules/services/services-getters.ts index 57ecbfc04..113753097 100644 --- a/src/store/modules/services/services-getters.ts +++ b/src/store/modules/services/services-getters.ts @@ -7,7 +7,25 @@ export const getters: GetterTree = { rate(state) { return Object.values(state[NODE_LABELS.RatesInfo]) }, + btcIndexer(state) { + return Object.values(state[NODE_LABELS.BtcIndexer]) + }, + dogeIndexer(state) { + return Object.values(state[NODE_LABELS.DogeIndexer]) + }, + ethIndexer(state) { + return Object.values(state[NODE_LABELS.EthIndexer]) + }, + klyIndexer(state) { + return Object.values(state[NODE_LABELS.KlyIndexer]) + }, services(state, getters) { - return [...getters.rate] + return [ + ...getters.rate, + ...getters.btcIndexer, + ...getters.dogeIndexer, + ...getters.ethIndexer, + ...getters.klyIndexer + ] } } diff --git a/src/store/modules/services/services-state.ts b/src/store/modules/services/services-state.ts index 660369025..1df23e662 100644 --- a/src/store/modules/services/services-state.ts +++ b/src/store/modules/services/services-state.ts @@ -3,5 +3,9 @@ import { NODE_LABELS } from '@/lib/nodes/constants' export const state: ServicesState = { [NODE_LABELS.RatesInfo]: {}, + [NODE_LABELS.BtcIndexer]: {}, + [NODE_LABELS.DogeIndexer]: {}, + [NODE_LABELS.EthIndexer]: {}, + [NODE_LABELS.KlyIndexer]: {}, useFastestService: true } diff --git a/src/store/modules/services/types.ts b/src/store/modules/services/types.ts index 3d8e32deb..bff513f91 100644 --- a/src/store/modules/services/types.ts +++ b/src/store/modules/services/types.ts @@ -2,17 +2,22 @@ import { NODE_LABELS } from '@/lib/nodes/constants' export type ServicesState = { [NODE_LABELS.RatesInfo]: Record + [NODE_LABELS.BtcIndexer]: Record + [NODE_LABELS.DogeIndexer]: Record + [NODE_LABELS.EthIndexer]: Record + [NODE_LABELS.KlyIndexer]: Record useFastestService: boolean } -export type AvailableService = 'rates-info' +export type AvailableService = + | 'rates-info' + | 'btc-indexer' + | 'doge-indexer' + | 'eth-indexer' + | 'kly-indexer' export type StatusPayload = { serviceType: AvailableService status: { url: string; active: boolean } } export type TogglePayload = { type: AvailableService; url: string; active: boolean } - -export type ServicesGetters = { - rate: (state: ServicesState) => { active: boolean }[] -} From 5b6e9cb8e5a180db3e69e90307cc604107f480e5 Mon Sep 17 00:00:00 2001 From: bludnic Date: Wed, 17 Jul 2024 02:22:59 +0100 Subject: [PATCH 107/218] feat(useEthTransactionQuery): fix queryKey --- src/hooks/queries/transaction/useEthTransactionQuery.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/queries/transaction/useEthTransactionQuery.ts b/src/hooks/queries/transaction/useEthTransactionQuery.ts index ca272e1b8..dcd6e311e 100644 --- a/src/hooks/queries/transaction/useEthTransactionQuery.ts +++ b/src/hooks/queries/transaction/useEthTransactionQuery.ts @@ -10,7 +10,7 @@ export function useEthTransactionQuery(transactionId: MaybeRef) { const store = useStore() return useQuery({ - queryKey: ['transaction', crypto, transactionId], + queryKey: ['transaction', Cryptos.ETH, transactionId], queryFn: () => eth.getEthTransaction(unref(transactionId), store.state.eth.address), initialData: {} as EthTransaction, retry: retryFactory(Cryptos.BTC, unref(transactionId)), From fefae16920e6ac88ef878861e52e83c81ab9357b Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 00:59:14 +0100 Subject: [PATCH 108/218] fix(isErc20): use optional chaining --- src/lib/constants/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/constants/index.js b/src/lib/constants/index.js index a96c4b553..bd09c6eae 100644 --- a/src/lib/constants/index.js +++ b/src/lib/constants/index.js @@ -77,7 +77,7 @@ export const INSTANT_SEND = Object.freeze([Cryptos.DASH]) // Some cryptos allows to save public data with a Tx export const ALLOW_TEXT_DATA = Object.freeze([Cryptos.KLY]) -export const isErc20 = (crypto) => CryptosInfo[crypto].type === 'ERC20' +export const isErc20 = (crypto) => CryptosInfo[crypto]?.type === 'ERC20' export const isEthBased = (crypto) => isErc20(crypto) || crypto === Cryptos.ETH From 39a92ab2050ed932987fe6afcac45898229dcbf4 Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:08:46 +0100 Subject: [PATCH 109/218] fix(useInconsistentStatus): fix ERC20 address --- .../transactions/hooks/useInconsistentStatus.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/transactions/hooks/useInconsistentStatus.ts b/src/components/transactions/hooks/useInconsistentStatus.ts index bbb9f4c08..31bea598c 100644 --- a/src/components/transactions/hooks/useInconsistentStatus.ts +++ b/src/components/transactions/hooks/useInconsistentStatus.ts @@ -2,7 +2,7 @@ import { computed, Ref } from 'vue' import { useStore } from 'vuex' import { useFindAdmTransaction } from './useFindAdmTransaction' import { useKVSCryptoAddress } from '@/hooks/queries/useKVSCryptoAddress.ts' -import { CryptoSymbol } from '@/lib/constants' +import { CryptoSymbol, isErc20 } from '@/lib/constants' import { getInconsistentStatus, InconsistentStatus } from '../utils/getInconsistentStatus' import { CoinTransaction } from '@/lib/nodes/types/transaction' @@ -12,7 +12,11 @@ export function useInconsistentStatus( ) { const store = useStore() - const mineCryptoAddress = computed(() => store.state[crypto.toLowerCase()].address) + const mineCryptoAddress = computed(() => { + if (isErc20(crypto)) return store.state.eth.address + + return store.state[crypto.toLowerCase()].address + }) const transactionId = computed(() => transaction.value?.id) const admTx = useFindAdmTransaction(transactionId) From 5c97f12590d6aed63214c5d9e547cc35e07af19e Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:09:08 +0100 Subject: [PATCH 110/218] fix(useInconsistentStatus): fix transaction param type --- .../hooks/useInconsistentStatus.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/components/transactions/hooks/useInconsistentStatus.ts b/src/components/transactions/hooks/useInconsistentStatus.ts index 31bea598c..7b40af568 100644 --- a/src/components/transactions/hooks/useInconsistentStatus.ts +++ b/src/components/transactions/hooks/useInconsistentStatus.ts @@ -4,10 +4,25 @@ import { useFindAdmTransaction } from './useFindAdmTransaction' import { useKVSCryptoAddress } from '@/hooks/queries/useKVSCryptoAddress.ts' import { CryptoSymbol, isErc20 } from '@/lib/constants' import { getInconsistentStatus, InconsistentStatus } from '../utils/getInconsistentStatus' -import { CoinTransaction } from '@/lib/nodes/types/transaction' +import { + BtcTransaction, + DashTransaction, + DogeTransaction, + Erc20Transaction, + EthTransaction, + KlyTransaction +} from '@/lib/nodes/types/transaction' export function useInconsistentStatus( - transaction: Ref, + transaction: Ref< + | BtcTransaction + | DogeTransaction + | DashTransaction + | KlyTransaction + | EthTransaction + | Erc20Transaction + | null + >, crypto: CryptoSymbol ) { const store = useStore() From b4859f410baf2f44429e6e7ebf64edbfcdb4f0b3 Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:15:24 +0100 Subject: [PATCH 111/218] fix(useTransactionQuery): remove ADM --- src/hooks/queries/transaction/useTransactionQuery.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hooks/queries/transaction/useTransactionQuery.ts b/src/hooks/queries/transaction/useTransactionQuery.ts index 2917c7067..4242c20bd 100644 --- a/src/hooks/queries/transaction/useTransactionQuery.ts +++ b/src/hooks/queries/transaction/useTransactionQuery.ts @@ -1,6 +1,5 @@ import { MaybeRef } from 'vue' import { CryptoSymbol, isErc20 } from '@/lib/constants' -import { useAdmTransactionQuery } from './useAdmTransactionQuery' import { useBtcTransactionQuery } from './useBtcTransactionQuery' import { useDogeTransactionQuery } from './useDogeTransactionQuery' import { useDashTransactionQuery } from './useDashTransactionQuery' @@ -9,7 +8,6 @@ import { useErc20TransactionQuery } from './useErc20TransactionQuery' import { useKlyTransactionQuery } from './useKlyTransactionQuery' const query = { - ADM: useAdmTransactionQuery, BTC: useBtcTransactionQuery, DOGE: useDogeTransactionQuery, DASH: useDashTransactionQuery, @@ -23,7 +21,6 @@ export function useTransactionQuery(transactionId: MaybeRef, crypto: Cry } switch (crypto) { - case 'ADM': case 'BTC': case 'DOGE': case 'DASH': From 12a81f58d32d4d2b2078376efe53b4ad30fb4490 Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:37:53 +0100 Subject: [PATCH 112/218] feat: fetch transaction status using Vue Query --- src/components/AChat/AChatMessage.vue | 12 ++-- src/components/AChat/AChatTransaction.vue | 72 +++++++------------ src/components/Chat/Chat.vue | 19 +---- src/components/ChatPreview.vue | 56 +++++++-------- src/hooks/queries/transaction/index.ts | 1 + .../transaction/useTransactionStatusQuery.ts | 36 ++++++++++ src/providers/TransactionProvider.vue | 45 ++++++++++++ 7 files changed, 141 insertions(+), 100 deletions(-) create mode 100644 src/hooks/queries/transaction/useTransactionStatusQuery.ts create mode 100644 src/providers/TransactionProvider.vue diff --git a/src/components/AChat/AChatMessage.vue b/src/components/AChat/AChatMessage.vue index 7e2ee6cf7..a866d3023 100644 --- a/src/components/AChat/AChatMessage.vue +++ b/src/components/AChat/AChatMessage.vue @@ -32,13 +32,15 @@
-
+
+ ⚭ +
{{ time }}
!isWelcomeChat(partnerId.value)) - const statusIcon = computed(() => tsIcon(props.status.virtualStatus)) + const statusIcon = computed(() => tsIcon(props.transaction.status)) const isOutgoingMessage = computed(() => isStringEqualCI(props.transaction.senderId, userId.value) ) diff --git a/src/components/AChat/AChatTransaction.vue b/src/components/AChat/AChatTransaction.vue index e5542d070..481fab01e 100644 --- a/src/components/AChat/AChatTransaction.vue +++ b/src/components/AChat/AChatTransaction.vue @@ -30,13 +30,24 @@
+ + +
@@ -87,7 +98,6 @@ import { useTransactionTime } from '@/components/AChat/hooks/useTransactionTime. import { NormalizedChatMessageTransaction } from '@/lib/chat/helpers' import { CryptoSymbol } from '@/lib/constants/cryptos' import { computed, watch, onMounted, defineComponent, PropType } from 'vue' -import { useI18n } from 'vue-i18n' import { useStore } from 'vuex' import { tsIcon, tsUpdatable, tsColor, Cryptos } from '@/lib/constants' @@ -97,9 +107,11 @@ import { timestampInSec } from '@/filters/helpers' import currencyFormatter from '@/filters/currencyAmountWithSymbol' import { useSwipeLeft } from '@/hooks/useSwipeLeft' import QuotedMessage from './QuotedMessage.vue' +import TransactionProvider from '@/providers/TransactionProvider.vue' export default defineComponent({ components: { + TransactionProvider, QuotedMessage }, props: { @@ -110,17 +122,10 @@ export default defineComponent({ dataId: { type: String }, - status: { - type: Object, - required: true - }, crypto: { - type: String, + type: String as PropType, default: 'ADM' }, - txTimestamp: { - required: true - }, /** * Highlight the message by applying a background flash effect */ @@ -138,16 +143,8 @@ export default defineComponent({ type: Boolean } }, - emits: [ - 'mount', - 'click:transaction', - 'click:transactionStatus', - 'click:quotedMessage', - 'swipe:left', - 'longpress' - ], + emits: ['click:transaction', 'click:quotedMessage', 'swipe:left', 'longpress'], setup(props, { emit }) { - const { t } = useI18n() const store = useStore() const userId = computed(() => store.state.address) @@ -155,20 +152,12 @@ export default defineComponent({ const time = useTransactionTime(props.transaction) const isCryptoSupported = computed(() => props.transaction.type in Cryptos) - const statusIcon = computed(() => tsIcon(props.status.virtualStatus)) - const statusTitle = computed(() => - t(`chats.transaction_statuses.${props.status.virtualStatus}`) - ) - const statusUpdatable = computed(() => - tsUpdatable(props.status.virtualStatus, props.crypto as CryptoSymbol) - ) - const statusColor = computed(() => tsColor(props.status.virtualStatus)) const historyRate = computed(() => { const amount = currencyAmount(props.transaction.amount, props.crypto) return ( '~' + store.getters['rate/historyRate']( - timestampInSec(props.crypto, props.txTimestamp), + timestampInSec(props.crypto, props.transaction.timestamp), amount, props.crypto ) @@ -181,15 +170,9 @@ export default defineComponent({ } } - const updateStatus = () => { - if (statusUpdatable.value) { - emit('click:transactionStatus', props.transaction.id) - } - } - const getHistoryRates = () => { store.dispatch('rate/getHistoryRates', { - timestamp: timestampInSec(props.crypto, props.txTimestamp) + timestamp: timestampInSec(props.crypto, props.transaction.timestamp) }) } @@ -198,14 +181,13 @@ export default defineComponent({ } watch( - () => props.txTimestamp, + () => props.transaction.timestamp, () => { getHistoryRates() } ) onMounted(() => { - emit('mount') getHistoryRates() }) @@ -221,13 +203,11 @@ export default defineComponent({ isStringEqualCI, currencyFormatter, - statusIcon, - statusTitle, - statusUpdatable, - statusColor, + tsIcon, + tsColor, + tsUpdatable, historyRate, onClickAmount, - updateStatus, onLongPress, onMove, diff --git a/src/components/Chat/Chat.vue b/src/components/Chat/Chat.vue index da6d0324c..9e48f654a 100644 --- a/src/components/Chat/Chat.vue +++ b/src/components/Chat/Chat.vue @@ -21,7 +21,6 @@ @@ -73,7 +87,7 @@ size="15" class="mr-1" /> - + @@ -84,7 +98,7 @@ From 2513c723fba75afc33fc149062df23e6006ec50e Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:39:33 +0100 Subject: [PATCH 113/218] refactor: remove transaction mixin --- src/mixins/transaction.js | 186 -------------------------------------- 1 file changed, 186 deletions(-) delete mode 100644 src/mixins/transaction.js diff --git a/src/mixins/transaction.js b/src/mixins/transaction.js deleted file mode 100644 index e5bd3695a..000000000 --- a/src/mixins/transaction.js +++ /dev/null @@ -1,186 +0,0 @@ -import { - Cryptos, - TransactionStatus as TS, - TransactionAdditionalStatus as TAS -} from '@/lib/constants' -import { verifyTransactionDetails } from '@/lib/txVerify' - -export default { - methods: { - /** - * Fetch transaction status from ETH, ERC20, DOGE modules. - * @param {{ id: string, type: string, hash: string }} admSpecialMessage - * @param {string} partnerId Partner ADM address - */ - fetchTransactionStatus(admSpecialMessage, partnerId) { - if (!admSpecialMessage || !partnerId) return - - const { type, hash, senderId, recipientId } = admSpecialMessage - if (type in Cryptos) { - // Don't need to fetch coin addresses for ADM txs - if (type !== Cryptos.ADM) this.fetchCryptoAddresses(type, recipientId, senderId) - // Update status, including ADM direct transfers and in-chat transfers - // Message txs are not processed here - this.fetchTransaction(type, hash, admSpecialMessage.timestamp) - } - }, - - /** - * Fetch transaction and save to state. - * @param {string} type Transaction type - * @param {string} hash Transaction hash - * @param {number} timestamp ADAMANT special message timestamp. If coin Tx is not known yet, set its timestamp to ADM rich message timestamp. Later it will be updated - */ - fetchTransaction(type, hash, timestamp) { - const cryptoModule = type.toLowerCase() - return this.$store.dispatch(`${cryptoModule}/getTransaction`, { hash, timestamp }) - }, - - /** - * Get crypto tx info from store - * @param {string} type Transaction type - * @param {string} hash Transaction hash - */ - getTransaction(type, hash) { - let transaction - if (type === 'ADM') { - transaction = this.$store.state.adm.transactions[hash] || {} - } else if (!Cryptos[type]) { - transaction = {} - } else { - transaction = this.$store.getters[`${type.toLowerCase()}/transaction`](hash) || {} - } - return transaction - }, - - /** - * Fetch recipientId & senderId crypto addresses. - * @param type Crypto name - * @param recipientId - * @param senderId - * @returns {Promise} - */ - fetchCryptoAddresses(type, recipientId, senderId) { - const recipientCryptoAddress = this.$store.dispatch('partners/fetchAddress', { - crypto: type, - partner: recipientId - }) - const senderCryptoAddress = this.$store.dispatch('partners/fetchAddress', { - crypto: type, - partner: senderId - }) - - return Promise.all([recipientCryptoAddress, senderCryptoAddress]) - }, - - /** - * Get Tx status with additional info to show in Chat, ChatPreview and TransactionTemplate - * @param {{ id: string, type: string, hash: string }} admSpecialMessage ADM message or ADM rich message of Tx transfer - * @param {object} coinTx in case it's not in-chat coin transfer, we have all the data already - * @returns {object} - */ - getTransactionStatus(admSpecialMessage, coinTx) { - const status = { - status: TS.PENDING, - virtualStatus: TS.PENDING, - inconsistentReason: '', - addStatus: TAS.NONE, - addDescription: '' - } - - // if no hash, it is an empty object - admSpecialMessage = - admSpecialMessage && (admSpecialMessage.hash || admSpecialMessage.id) - ? admSpecialMessage - : undefined - - if (!admSpecialMessage && !coinTx) return status - status.status = admSpecialMessage ? admSpecialMessage.status : coinTx.status - status.virtualStatus = status.status - - // we don't need all this in case of not in-chat coin transfer - if (admSpecialMessage) { - const { type, senderId, recipientId } = admSpecialMessage - const hash = admSpecialMessage.hash || admSpecialMessage.id - - // ADM is a special case when using sockets - if (type === Cryptos.ADM || type === 0 || type === 8 || type === 'message') { - if (admSpecialMessage.status === TS.REGISTERED) { - // If it's a message, getChats() in adamant-api.js will update height and confirmations later, - // But now we must show Tx as confirmed - if (type === 'message') { - status.virtualStatus = TS.CONFIRMED - status.addStatus = TAS.ADM_REGISTERED - status.addDescription = this.$t('transaction.statuses_add.adm_registered') - } else { - // All transactions we get via socket are shown in chats, including ADM direct transfers - // Currently, we don't update confirmations for direct transfers, see getChats() in adamant-api.js - // So we'll update confirmations here - const transfer = this.$store.state.adm.transactions[hash] - if (transfer && (transfer.height || transfer.confirmations > 0)) { - status.status = TS.CONFIRMED - status.virtualStatus = status.status - } else { - this.fetchTransaction('ADM', hash, admSpecialMessage.timestamp) - } - } - } - return status - } else if (!Cryptos[type]) { - // if crypto is not supported - status.status = TS.UNKNOWN - status.virtualStatus = status.status - return status - } - - const getterName = type.toLowerCase() + '/transaction' - const getter = this.$store.getters[getterName] - if (!getter) return status - - coinTx = getter(hash) - status.status = (coinTx && coinTx.status) || TS.PENDING - status.virtualStatus = status.status - - const recipientCryptoAddress = this.$store.getters['partners/cryptoAddress']( - recipientId, - type - ) - const senderCryptoAddress = this.$store.getters['partners/cryptoAddress'](senderId, type) - - // do not update status until cryptoAddresses and transaction are received - if (!recipientCryptoAddress || !senderCryptoAddress || !coinTx) { - status.status = TS.PENDING - status.virtualStatus = status.status - return status - } - - // check if Tx is not a fake - // we are unable to check status.status === TS.REGISTERED txs, as their timestamps are Date.now() - if (status.status === TS.CONFIRMED) { - const txVerify = verifyTransactionDetails(coinTx, admSpecialMessage, { - recipientCryptoAddress, - senderCryptoAddress - }) - if (!txVerify.isTxConsistent) { - status.status = TS.INVALID - status.virtualStatus = status.status - status.inconsistentReason = txVerify.txInconsistentReason - return status - } - } - } - - if (status.status === TS.REGISTERED) { - // Dash InstantSend transactions must be shown as confirmed - // don't need to verify timestamp, as such txs are fresh - if (coinTx.instantsend) { - status.virtualStatus = TS.CONFIRMED - status.addStatus = TAS.INSTANT_SEND - status.addDescription = this.$t('transaction.statuses_add.instant_send') - } - } - - return status - } - } -} From ae75e7d6e954b75b300cafc1ce8626531815463c Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:41:11 +0100 Subject: [PATCH 114/218] refactor: remove unused hook --- src/hooks/useTransactionStatus.ts | 178 ------------------------------ 1 file changed, 178 deletions(-) delete mode 100644 src/hooks/useTransactionStatus.ts diff --git a/src/hooks/useTransactionStatus.ts b/src/hooks/useTransactionStatus.ts deleted file mode 100644 index 7dbef527a..000000000 --- a/src/hooks/useTransactionStatus.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { - Cryptos, - TransactionAdditionalStatus as TAS, - TransactionStatus as TS, - TransactionStatusType -} from '@/lib/constants' -import { verifyTransactionDetails } from '@/lib/txVerify' -import { computed, ComputedRef, onMounted } from 'vue' -import { useI18n } from 'vue-i18n' -import { useStore } from 'vuex' - -export function useTransactionStatus(admTxRef: ComputedRef, coinTxRef: ComputedRef) { - const { t } = useI18n() - const store = useStore() - - onMounted(() => { - if (!admTxRef || !admTxRef.value) return - - const { status, type, timestamp } = admTxRef.value - const hash = admTxRef.value.hash || admTxRef.value.id - - if (status === TS.REGISTERED && (type === Cryptos.ADM || type === 0 || type === 8)) { - const transfer = store.state.adm.transactions[hash] - - if ( - !transfer.height && - (transfer.confirmations === undefined || transfer.confirmations <= 0) - ) { - store.dispatch(`adm/getTransaction`, { hash, timestamp }) - } - } - }) - - const computedStatus = computed(() => { - const status: { - status: TransactionStatusType - virtualStatus: TransactionStatusType - inconsistentReason: string - addStatus: (typeof TAS)[keyof typeof TAS] - addDescription: string - } = { - status: TS.PENDING, - virtualStatus: TS.PENDING, - inconsistentReason: '', - addStatus: TAS.NONE, - addDescription: '' - } - - // if no hash, it is an empty object - const admSpecialMessage = - admTxRef.value && (admTxRef.value.hash || admTxRef.value.id) ? admTxRef.value : undefined - - if (!admSpecialMessage && (!coinTxRef || !coinTxRef.value)) return status - status.status = admSpecialMessage ? admSpecialMessage.status : coinTxRef.value.status - status.virtualStatus = status.status - - // we don't need all this in case of not in-chat coin transfer - if (admSpecialMessage) { - const { type, senderId, recipientId } = admSpecialMessage - const hash = admSpecialMessage.hash || admSpecialMessage.id - - // ADM is a special case when using sockets - if (type === Cryptos.ADM || type === 0 || type === 8 || type === 'message') { - if (admSpecialMessage.status === TS.REGISTERED) { - // If it's a message, getChats() in adamant-api.js will update height and confirmations later, - // But now we must show Tx as confirmed - if (type === 'message') { - status.virtualStatus = TS.CONFIRMED - status.addStatus = TAS.ADM_REGISTERED - status.addDescription = t('transaction.statuses_add.adm_registered') - } else { - // All transactions we get via socket are shown in chats, including ADM direct transfers - // Currently, we don't update confirmations for direct transfers, see getChats() in adamant-api.js - // So we'll update confirmations here - const transfer = store.state.adm.transactions[hash] - if (transfer && (transfer.height || transfer.confirmations > 0)) { - status.status = TS.CONFIRMED - status.virtualStatus = status.status - } else { - // @todo remove - // this.fetchTransaction('ADM', hash, admSpecialMessage.timestamp) - } - } - } - return status - // @ts-expect-error-next-line - } else if (!Cryptos[type]) { - // if crypto is not supported - status.status = TS.UNKNOWN - status.virtualStatus = status.status - return status - } - - const getterName = type.toLowerCase() + '/transaction' - const getter = store.getters[getterName] - if (!getter) return status - - const coinTx = getter(hash) - status.status = (coinTx && coinTx.status) || TS.PENDING - status.virtualStatus = status.status - - const recipientCryptoAddress = store.getters['partners/cryptoAddress'](recipientId, type) - const senderCryptoAddress = store.getters['partners/cryptoAddress'](senderId, type) - - // do not update status until cryptoAddresses and transaction are received - if (!recipientCryptoAddress || !senderCryptoAddress || !coinTx) { - status.status = TS.PENDING - status.virtualStatus = status.status - return status - } - - // check if Tx is not a fake - // we are unable to check status.status === TS.REGISTERED txs, as their timestamps are Date.now() - if (status.status === TS.CONFIRMED) { - const txVerify = verifyTransactionDetails(coinTx, admSpecialMessage, { - recipientCryptoAddress, - senderCryptoAddress - }) - if (!txVerify.isTxConsistent) { - status.status = TS.INVALID - status.virtualStatus = status.status - // @ts-expect-error-next-line - status.inconsistentReason = txVerify.txInconsistentReason - return status - } - } - } - - if (status.status === TS.REGISTERED) { - // Dash InstantSend transactions must be shown as confirmed - // don't need to verify timestamp, as such txs are fresh - if (coinTxRef.value.instantsend) { - status.virtualStatus = TS.CONFIRMED - status.addStatus = TAS.INSTANT_SEND - status.addDescription = t('transaction.statuses_add.instant_send') - } - } - - return status - }) - - const fetchTransactionStatus = () => { - if (!admTxRef || !admTxRef.value) return - - const { type, hash, senderId, recipientId, timestamp } = admTxRef.value - if (type in Cryptos) { - // Don't need to fetch coin addresses for ADM txs - if (type !== Cryptos.ADM) fetchCryptoAddresses(type, recipientId, senderId) - // Update status, including ADM direct transfers and in-chat transfers - // Message txs are not processed here - fetchTransaction(type, hash, timestamp) - } - } - - const fetchCryptoAddresses = (type: string, recipientId: string, senderId: string) => { - const recipientCryptoAddress = store.dispatch('partners/fetchAddress', { - crypto: type, - partner: recipientId - }) - const senderCryptoAddress = store.dispatch('partners/fetchAddress', { - crypto: type, - partner: senderId - }) - - return Promise.all([recipientCryptoAddress, senderCryptoAddress]) - } - - const fetchTransaction = (type: string, hash: string, timestamp: number) => { - const cryptoModule = type.toLowerCase() - - return store.dispatch(`${cryptoModule}/getTransaction`, { hash, timestamp }) - } - - return { - status: computedStatus, - fetchTransactionStatus - } -} From 201852b5f0bed60105da74983269613b262f3177 Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:49:30 +0100 Subject: [PATCH 115/218] fix(useTransactionStatusQuery): fix status --- src/hooks/queries/transaction/useTransactionStatusQuery.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/queries/transaction/useTransactionStatusQuery.ts b/src/hooks/queries/transaction/useTransactionStatusQuery.ts index a447e52d2..49da44ce3 100644 --- a/src/hooks/queries/transaction/useTransactionStatusQuery.ts +++ b/src/hooks/queries/transaction/useTransactionStatusQuery.ts @@ -17,9 +17,9 @@ export function useTransactionStatusQuery( const status = computed(() => { if (isFetching.value) return TransactionStatus.PENDING - if (fetchStatus.value === 'error') return TransactionStatus.UNKNOWN + if (fetchStatus.value === 'error') return TransactionStatus.INVALID if (fetchStatus.value === 'success') { - if (inconsistentStatus.value) return TransactionStatus.INVALID + if (inconsistentStatus.value) return TransactionStatus.UNKNOWN return TransactionStatus.CONFIRMED } From c837748004fa3230ac754e485d94e71ac22d1c6d Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:52:44 +0100 Subject: [PATCH 116/218] fix: fix build errors --- src/components/transactions/Transaction.vue | 2 ++ src/components/transactions/utils/getInconsistentStatus.ts | 5 ++--- src/hooks/address/index.ts | 2 -- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/transactions/Transaction.vue b/src/components/transactions/Transaction.vue index 8f3b948e5..3ec5001ec 100644 --- a/src/components/transactions/Transaction.vue +++ b/src/components/transactions/Transaction.vue @@ -229,6 +229,8 @@ export default defineComponent({ const recipient = computed(() => props.recipients?.join(',') ?? transaction.value?.senderId) const hasMessages = computed(() => { + if (!props.partner) return false + const chat = store.state.chat.chats[props.partner] return chat && chat.messages && Object.keys(chat.messages).length > 0 }) diff --git a/src/components/transactions/utils/getInconsistentStatus.ts b/src/components/transactions/utils/getInconsistentStatus.ts index d8821cf0f..3b4466663 100644 --- a/src/components/transactions/utils/getInconsistentStatus.ts +++ b/src/components/transactions/utils/getInconsistentStatus.ts @@ -87,9 +87,8 @@ function verifyTimestamp( ) { const delta = Math.abs(transactionTimestamp - specialMessageTimestamp) / 1000 - // @todo fix adamant-wallets schema - const mainCoin = CryptosInfo[coin].mainCoin || coin - const { txConsistencyMaxTime } = CryptosInfo[mainCoin] + const mainCoin = (CryptosInfo[coin] as any)?.mainCoin || coin // @todo fix type in adamant-wallets schema + const { txConsistencyMaxTime } = CryptosInfo[mainCoin as CryptoSymbol] if (txConsistencyMaxTime) { return delta < txConsistencyMaxTime diff --git a/src/hooks/address/index.ts b/src/hooks/address/index.ts index caacbcb1c..a9316f044 100644 --- a/src/hooks/address/index.ts +++ b/src/hooks/address/index.ts @@ -1,4 +1,2 @@ -export * from './useFindAdmAddress' -export * from './useFindAdmTransaction' export * from './useFormatADMAddress' export * from './usePartnerCryptoAddress' From 05baf5ba41f7f4844b97b0cccf024312c5cde101 Mon Sep 17 00:00:00 2001 From: bludnic Date: Thu, 18 Jul 2024 01:55:58 +0100 Subject: [PATCH 117/218] refactor: rename TransactionTemplate component --- src/components/transactions/AdmTransaction.vue | 6 +++--- src/components/transactions/BtcTransaction.vue | 6 +++--- src/components/transactions/Erc20Transaction.vue | 6 +++--- src/components/transactions/EthTransaction.vue | 6 +++--- src/components/transactions/KlyTransaction.vue | 6 +++--- .../{Transaction.vue => TransactionTemplate.vue} | 0 6 files changed, 15 insertions(+), 15 deletions(-) rename src/components/transactions/{Transaction.vue => TransactionTemplate.vue} (100%) diff --git a/src/components/transactions/AdmTransaction.vue b/src/components/transactions/AdmTransaction.vue index b8bd6eeec..8e73b72fc 100644 --- a/src/components/transactions/AdmTransaction.vue +++ b/src/components/transactions/AdmTransaction.vue @@ -1,5 +1,5 @@